Skip to content

Commit

Permalink
feat: add new setup test env functions
Browse files Browse the repository at this point in the history
Closes #354
Closes #2755
  • Loading branch information
ahnpnl committed Nov 15, 2024
1 parent 8a8820e commit 21c0238
Show file tree
Hide file tree
Showing 30 changed files with 437 additions and 58 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ src/config/setup-jest.ts
coverage
src/transformers/jit_transform.js
index.html
*.mjs
3 changes: 2 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const baseJsTsConfig = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.eslint.json',
sourceType: 'module',
},
rules: {
'@typescript-eslint/no-empty-function': 'error',
Expand Down Expand Up @@ -71,7 +72,7 @@ module.exports = {
overrides: [
{
...baseJsTsConfig,
files: ['*.ts', '*.js'],
files: ['*.ts', '*.js', '*.mts'],
extends: [
'plugin:@angular-eslint/recommended',
'plugin:@angular-eslint/template/process-inline-templates',
Expand Down
4 changes: 3 additions & 1 deletion examples/example-app-monorepo/apps/app1/setup-jest-esm.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
import 'jest-preset-angular/setup-jest.mjs';
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone/index.mjs';
import './jest-global-mocks';

setupZoneTestEnv();
4 changes: 3 additions & 1 deletion examples/example-app-monorepo/apps/app1/setup-jest.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
import 'jest-preset-angular/setup-jest';
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone';
import './jest-global-mocks';

setupZoneTestEnv();
4 changes: 3 additions & 1 deletion examples/example-app-monorepo/libs/user/setup-jest-esm.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
import 'jest-preset-angular/setup-jest.mjs';
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone/index.mjs';
import './jest-global-mocks';

setupZoneTestEnv();
4 changes: 3 additions & 1 deletion examples/example-app-monorepo/libs/user/setup-jest.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
import 'jest-preset-angular/setup-jest';
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone';
import './jest-global-mocks';

setupZoneTestEnv();
4 changes: 3 additions & 1 deletion examples/example-app-v16/setup-jest-esm.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
import 'jest-preset-angular/setup-jest.mjs';
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone/index.mjs';
import './jest-global-mocks';

setupZoneTestEnv();
4 changes: 3 additions & 1 deletion examples/example-app-v16/setup-jest.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
import 'jest-preset-angular/setup-jest';
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone';
import './jest-global-mocks';

setupZoneTestEnv();
4 changes: 3 additions & 1 deletion examples/example-app-v17/setup-jest-esm.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
import 'jest-preset-angular/setup-jest.mjs';
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone/index.mjs';
import './jest-global-mocks';

setupZoneTestEnv();
4 changes: 3 additions & 1 deletion examples/example-app-v17/setup-jest.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
import 'jest-preset-angular/setup-jest';
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone';
import './jest-global-mocks';

setupZoneTestEnv();
4 changes: 3 additions & 1 deletion examples/example-app-v18/setup-jest-esm.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
import 'jest-preset-angular/setup-jest.mjs';
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone/index.mjs';
import './jest-global-mocks';

setupZoneTestEnv();
4 changes: 3 additions & 1 deletion examples/example-app-v18/setup-jest.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
import 'jest-preset-angular/setup-jest';
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone';
import './jest-global-mocks';

setupZoneTestEnv();
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
import 'jest-preset-angular/setup-jest.mjs';
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone/index.mjs';
import './jest-global-mocks';

setupZoneTestEnv();
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
import 'jest-preset-angular/setup-jest';
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone';
import './jest-global-mocks';

setupZoneTestEnv();
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
import 'jest-preset-angular/setup-jest.mjs';
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone/index.mjs';
import './jest-global-mocks';

setupZoneTestEnv();
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
import 'jest-preset-angular/setup-jest';
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone';
import './jest-global-mocks';

setupZoneTestEnv();
1 change: 1 addition & 0 deletions scripts/test-examples.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const executeTest = (projectPath) => {
'package.json',
'setup-jest.js',
'setup-jest.mjs',
'setup-env',
].forEach((asset) => {
const assetToReplace = join(projectPath, 'node_modules', 'jest-preset-angular', asset);
const assetToCopy = join(rootDir, asset);
Expand Down
19 changes: 19 additions & 0 deletions setup-env/utils.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { TextDecoder, TextEncoder } from 'util';

export const polyfillEncoder = () => {
if (typeof globalThis.TextEncoder === 'undefined') {
globalThis.TextEncoder = TextEncoder;
globalThis.TextDecoder = TextDecoder;
}
};

export const resolveTestEnvOptions = (options) => {
const globalTestEnvOptions = globalThis.ngJest?.testEnvironmentOptions;
if (globalTestEnvOptions) {
console.warn(
'Setting testEnvironmentOptions via globalThis.ngJest is deprecated. Please provide testEnvironmentOptions via function argument',
);
}

return globalTestEnvOptions ?? options;
};
3 changes: 3 additions & 0 deletions setup-env/zone/index.d.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import type { TestEnvironmentOptions } from '@angular/core/testing';

export declare const setupZoneTestEnv: (options?: TestEnvironmentOptions) => void;
6 changes: 6 additions & 0 deletions setup-env/zone/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { TestEnvironmentOptions } from '@angular/core/testing';

declare const _default: {
setupZoneTestEnv: (options?: TestEnvironmentOptions) => void;
};
export = _default;
43 changes: 43 additions & 0 deletions setup-env/zone/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
require('zone.js');
require('zone.js/testing');

const { TextEncoder, TextDecoder } = require('util');

const { getTestBed } = require('@angular/core/testing');
const {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting,
} = require('@angular/platform-browser-dynamic/testing');

const polyfillEncoder = () => {
if (typeof globalThis.TextEncoder === 'undefined') {
globalThis.TextEncoder = TextEncoder;
globalThis.TextDecoder = TextDecoder;
}
};

const resolveTestEnvOptions = (options) => {
const globalTestEnvOptions = globalThis.ngJest?.testEnvironmentOptions;
if (globalTestEnvOptions) {
console.warn(
'Setting testEnvironmentOptions via globalThis.ngJest is deprecated. Please provide testEnvironmentOptions via function argument',
);
}

return globalTestEnvOptions ?? options;
};

const setupZoneTestEnv = (options) => {
polyfillEncoder();
const testEnvironmentOptions = resolveTestEnvOptions(options);

getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting(),
testEnvironmentOptions,
);
};

module.exports = {
setupZoneTestEnv,
};
18 changes: 18 additions & 0 deletions setup-env/zone/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import 'zone.js';
import 'zone.js/testing';

import { getTestBed } from '@angular/core/testing';
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';

import { polyfillEncoder, resolveTestEnvOptions } from '../utils.mjs';

export const setupZoneTestEnv = (options) => {
polyfillEncoder();
const testEnvironmentOptions = resolveTestEnvOptions(options);

getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting(),
testEnvironmentOptions,
);
};
3 changes: 3 additions & 0 deletions setup-env/zoneless/index.d.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import type { TestEnvironmentOptions } from '@angular/core/testing';

export declare const setupZonelessTestEnv: (options?: TestEnvironmentOptions) => void;
6 changes: 6 additions & 0 deletions setup-env/zoneless/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { TestEnvironmentOptions } from '@angular/core/testing';

declare const _default: {
setupZonelessTestEnv: (options?: TestEnvironmentOptions) => void;
};
export = _default;
11 changes: 11 additions & 0 deletions setup-env/zoneless/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const setupZonelessTestEnv = (_options) => {
throw Error(
'Zoneless testing environment only works when running Jest in ESM mode with Jest 29. ' +
'Jest 30+ will support to work with CommonJS mode.',
);
};

module.exports = {
setupZonelessTestEnv,
};
39 changes: 39 additions & 0 deletions setup-env/zoneless/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { ErrorHandler, NgModule, provideExperimentalZonelessChangeDetection } from '@angular/core';
import { getTestBed } from '@angular/core/testing';
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';

import { polyfillEncoder, resolveTestEnvOptions } from '../utils.mjs';

export const setupZonelessTestEnv = (options) => {
if (typeof provideExperimentalZonelessChangeDetection !== 'undefined') {
polyfillEncoder();
const testEnvironmentOptions = resolveTestEnvOptions(options);
@NgModule({
providers: [
provideExperimentalZonelessChangeDetection(),
{
provide: ErrorHandler,
useValue: {
handleError: (e) => {
throw e;
},
},
},
],
})
export class TestModule {}

getTestBed().initTestEnvironment(
[BrowserDynamicTestingModule, TestModule],
platformBrowserDynamicTesting(),
testEnvironmentOptions,
);

return;
}

throw Error(
'Cannot find provideExperimentalZonelessChangeDetection() to setup zoneless testing environment. ' +
'Please use setupZoneTestEnv() from jest-preset-angular/setup-env/setup-zone-env.mjs instead.',
);
};
66 changes: 66 additions & 0 deletions src/config/setup-jest.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,39 @@ describe('setup-jest', () => {

expect(globalThis.TextEncoder).toBeDefined();
});

it('should call getTestBed() and initTestEnvironment() with the testEnvironmentOptions passed as argument with setupZoneTestEnv()', async () => {
const { setupZoneTestEnv } = await import('../../setup-env/zone/index.js');

setupZoneTestEnv({
teardown: {
destroyAfterEach: false,
rethrowErrors: true,
},
errorOnUnknownElements: true,
errorOnUnknownProperties: true,
});

expect(mockZoneJs).toHaveBeenCalled();
expect(mockZoneJsTesting).toHaveBeenCalled();
assertOnInitTestEnv();
expect(mockInitTestEnvironment.mock.calls[0][2]).toEqual({
teardown: {
destroyAfterEach: false,
rethrowErrors: true,
},
errorOnUnknownElements: true,
errorOnUnknownProperties: true,
});
});

it('should always have TextEncoder in globalThis with setupZoneTestEnv()', async () => {
const { setupZoneTestEnv } = await import('../../setup-env/zone/index.js');

setupZoneTestEnv();

expect(globalThis.TextEncoder).toBeDefined();
});
});

describe('for ESM setup-jest, test environment initialization', () => {
Expand Down Expand Up @@ -120,5 +153,38 @@ describe('setup-jest', () => {

expect(globalThis.TextEncoder).toBeDefined();
});

it('should call getTestBed() and initTestEnvironment() with the testEnvironmentOptions passed as argument with setupZoneTestEnv()', async () => {
const { setupZoneTestEnv } = await import('../../setup-env/zone/index.mjs');

setupZoneTestEnv({
teardown: {
destroyAfterEach: false,
rethrowErrors: true,
},
errorOnUnknownElements: true,
errorOnUnknownProperties: true,
});

expect(mockZoneJs).toHaveBeenCalled();
expect(mockZoneJsTesting).toHaveBeenCalled();
assertOnInitTestEnv();
expect(mockInitTestEnvironment.mock.calls[0][2]).toEqual({
teardown: {
destroyAfterEach: false,
rethrowErrors: true,
},
errorOnUnknownElements: true,
errorOnUnknownProperties: true,
});
});

it('should always have TextEncoder in globalThis with setupZoneTestEnv()', async () => {
const { setupZoneTestEnv } = await import('../../setup-env/zone/index.mjs');

setupZoneTestEnv();

expect(globalThis.TextEncoder).toBeDefined();
});
});
});
Loading

0 comments on commit 21c0238

Please sign in to comment.