Skip to content

Commit

Permalink
test: improvments + test helpers
Browse files Browse the repository at this point in the history
  • Loading branch information
huafu committed Aug 9, 2018
1 parent faae274 commit 9343c7d
Show file tree
Hide file tree
Showing 42 changed files with 6,210 additions and 439 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jspm_packages
# tests specific
tests/simple-long-path/long-src-path
# is linked to the temp dir of the os
e2e/__e2e_workdir_link__
e2e/__workdir_synlink__

# binaries
*.tgz
2 changes: 1 addition & 1 deletion e2e/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
- `__templates__`: contains the package dependency templates for test cases
- `__templates__/default`: is the default template
- `__tests__`: contains the actual tests
- `__e2e_workdir_link__`: is created during a test run and is a symbolic link to a subfolder in the temp folder of the OS where all test cases are installed
- `__workdir_synlink__`: is created during a test run and is a symbolic link to a subfolder in the temp folder of the OS where all test cases are installed


## Test helpers
Expand Down
14 changes: 14 additions & 0 deletions e2e/__cases__/hoisting/Hello.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Hello } from './Hello';

jest.mock('./Hello', () => ({ Hello() {} }));

describe('Hello Class', () => {
// tslint:disable-next-line:variable-name
const OriginalClass = require.requireActual('./Hello').Hello;
it('should create a new mocked Hello', () => {
const hello = new Hello('foo');
expect(hello.msg).toBeUndefined();
expect(hello).not.toBeInstanceOf(OriginalClass);
expect(hello).toHaveProperty('mock');
});
});
3 changes: 3 additions & 0 deletions e2e/__cases__/hoisting/Hello.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export class Hello {
constructor(readonly msg: string) {}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
declare var jest, describe, it, expect;

import { Hello } from '../Hello';
import { Hello } from './Hello';

describe('Hello Class', () => {
it('should create a new Hello', () => {
Expand Down
10 changes: 0 additions & 10 deletions e2e/__cases__/simple/package.json

This file was deleted.

5 changes: 0 additions & 5 deletions e2e/__cases__/simple/tsconfig.json

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { echo } from '../src/echo';
import { echo } from './echo';

describe('echo', () => {
it('echoes', () => {
Expand Down
File renamed without changes.
9 changes: 0 additions & 9 deletions e2e/__cases__/source-maps/package.json

This file was deleted.

10 changes: 0 additions & 10 deletions e2e/__cases__/source-maps/test/jest.config.json

This file was deleted.

13 changes: 0 additions & 13 deletions e2e/__cases__/source-maps/test/tsconfig.json

This file was deleted.

20 changes: 0 additions & 20 deletions e2e/__cases__/source-maps/tsconfig.json

This file was deleted.

12 changes: 12 additions & 0 deletions e2e/__helpers__/templates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export enum PackageSets {
default = 'default',
babel6 = 'with-babel-6',
babel7 = 'with-babel-7',
jest22 = 'with-jest-22',
}
export const allPackageSets = [
PackageSets.default,
PackageSets.babel6,
PackageSets.babel7,
PackageSets.jest22,
];
131 changes: 88 additions & 43 deletions e2e/__helpers__/test-case.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,47 @@ import { join } from 'path';
import * as Paths from '../../scripts/paths';
import * as fs from 'fs-extra';

const TEMPLATE_EXCLUDED_ITEMS = [
'node_modules',
'package.json',
'package-lock.json',
];
const jestDescribe = describe;
const jestIt = it;
const jestExpect = expect;

const TEMPLATE_EXCLUDED_ITEMS = ['node_modules', 'package-lock.json'];

type RunWithTemplatesIterator = (
runtTest: () => TestRunResult,
templateName: string,
) => void;
interface RunWithTemplatesOptions {
iterator?: RunWithTemplatesIterator;
logUnlessStatus?: number;
}
interface WithTemplatesIteratorOptions {
describe?: string | false;
it?: string;
expect?: RunWithTemplatesIterator;
}

export function withTemplatesIterator({
describe = 'with template "__TEMPLATE_NAME__"',
it = 'should run as expected',
expect = runTest => {
jestExpect(runTest()).toMatchSnapshot();
},
}: WithTemplatesIteratorOptions = {}): RunWithTemplatesIterator {
return (runTest, name) => {
const interpolate = (msg: string) => msg.replace('__TEMPLATE_NAME__', name);
if (describe) {
jestDescribe(interpolate(describe), () => {
jestIt(interpolate(it), () => expect(runTest, name));
});
} else {
jestIt(interpolate(it), () => expect(runTest, name));
}
};
}

class TestCaseRunDescriptor {
// tslint:disable-next-line:variable-name
protected _options: RunTestOptions;
// tslint:disable-next-line:variable-name
protected _sourcePackageJson: any;

constructor(readonly name: string, options: RunTestOptions = {}) {
Expand All @@ -37,12 +68,12 @@ class TestCaseRunDescriptor {
);
}

get templateName() {
get templateName(): string {
if (!this._options.template) {
// read the template from the package field if it is not given
this._options.template = this.sourcePackageJson.e2eTemplate || 'default';
}
return this._options.template;
return this._options.template as string;
}

run(logUnlessStatus?: number): TestRunResult {
Expand All @@ -62,20 +93,9 @@ class TestCaseRunDescriptor {
}

runWithTemplates<T extends string>(
logUnlessStatus: number,
// tslint:disable-next-line:trailing-comma
...templates: T[]
): TestRunResultsMap<T>;
runWithTemplates<T extends string>(...templates: T[]): TestRunResultsMap<T>;
runWithTemplates<T extends string>(
logUnlessStatus: number | T,
// tslint:disable-next-line:trailing-comma
...templates: T[]
templates: T[],
{ iterator, logUnlessStatus }: RunWithTemplatesOptions = {},
): TestRunResultsMap<T> {
if (typeof logUnlessStatus !== 'number') {
templates.unshift(logUnlessStatus);
logUnlessStatus = undefined;
}
if (templates.length < 1) {
throw new RangeError(
`There must be at least one template to run the test case with.`,
Expand All @@ -92,7 +112,16 @@ class TestCaseRunDescriptor {
...this._options,
template,
});
map[template as string] = desc.run(logUnlessStatus as number);
const runTest = () => {
const out = desc.run(logUnlessStatus);
map[template] = { ...out };
return out;
};
if (iterator) {
iterator(runTest, template);
} else {
runTest();
}
return map;
},
{} as TestRunResultsMap<T>,
Expand Down Expand Up @@ -129,13 +158,15 @@ export default function configureTestCase(
return new TestCaseRunDescriptor(name, options);
}

const PASS_MARKS = ['✓', '√'];
const FAIL_MARKS = ['✕', '×'];
// first one of each must be the most compatible one
const PASS_MARKS = ['√', '✓'];
const FAIL_MARKS = ['×', '✕'];
const normalizeTestMark = (mark: string): string => {
if (PASS_MARKS.includes(mark)) return 'P'; // tslint:disable-line
if (FAIL_MARKS.includes(mark)) return 'F'; // tslint:disable-line
if (PASS_MARKS.includes(mark)) return PASS_MARKS[0]; // tslint:disable-line
if (FAIL_MARKS.includes(mark)) return FAIL_MARKS[0]; // tslint:disable-line
return '?';
};

export function sanitizeOutput(output: string): string {
let out: string = output
.trim()
Expand All @@ -158,16 +189,23 @@ export function sanitizeOutput(output: string): string {
return out;
}

export function templateNameForPath(path: string): string {
const e2eFile = join(path, '.ts-jest-e2e.json');
if (fs.existsSync(e2eFile)) {
return require(e2eFile).template || 'default';
}
return 'default';
}

export function run(
name: string,
{ args = [], env = {}, template }: RunTestOptions = {},
): TestRunResult {
// we need to know if there is a test script, and if so use it instead of starting jest
const pkg = require(join(Paths.e2eSourceDir, name, 'package.json'));
if (!template) {
template = pkg.e2eTempalte || 'default';
}
const dir = prepareTest(name, template);
const dir = prepareTest(
name,
template || templateNameForPath(join(Paths.e2eSourceDir, name)),
);
const pkg = require(join(dir, 'package.json'));

const prefix =
pkg.scripts && pkg.scripts.test
Expand Down Expand Up @@ -215,24 +253,31 @@ function prepareTest(name: string, template: string): string {
// ensure directory exists
fs.mkdirpSync(caseDir);

// copy source and test files
fs.copySync(sourceDir, caseDir);

// link the node_modules dir
if (!fs.existsSync(join(caseDir, 'node_modules'))) {
fs.symlinkSync(
join(templateDir, 'node_modules'),
join(caseDir, 'node_modules'),
);
// link the node_modules dir if the template has
const tmplModulesDir = join(templateDir, 'node_modules');
const caseModulesDir = join(caseDir, 'node_modules');
if (!fs.existsSync(caseModulesDir) && fs.existsSync(tmplModulesDir)) {
fs.symlinkSync(tmplModulesDir, caseModulesDir);
}

// copy all other files from the template to the case dir
// copy files from the template to the case dir
fs.readdirSync(templateDir).forEach(item => {
if (TEMPLATE_EXCLUDED_ITEMS.includes(item)) {
return;
}
fs.copySync(join(templateDir, item), join(caseDir, item));
});

// copy source and test files
fs.copySync(sourceDir, caseDir);

// create a package.json if it does not exists, and/or enforce the package name
const pkgFile = join(caseDir, 'package.json');
const pkg: any = fs.existsSync(pkgFile) ? fs.readJsonSync(pkgFile) : {};
pkg.name = name;
pkg.private = true;
pkg.version = `0.0.0-mock0`;
fs.outputJsonSync(pkgFile, pkg, { spaces: 2 });

return caseDir;
}
6 changes: 3 additions & 3 deletions e2e/__templates__/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Let's say you want to use your lately created `with-lodash` template with a `my-

1. the test case should be run only with this template:

- in `e2e/__cases__/my-case/package.json` set the `e2eTempalte` to `"with-lodash"`
- in `e2e/__cases__/my-case/.ts-jest-e2e.json` set the `template` key to `"with-lodash"`
- in `e2e/__tests__/my-case.spec.ts`:

```ts
Expand All @@ -41,7 +41,7 @@ Let's say you want to use your lately created `with-lodash` template with a `my-
})
```

2. the test case is already been used with another template (its `package.json` has another value in `e2eTemplate`):
2. the test case is already been used with another template or you want to force it in the test:

- update the test `e2e/__tests__/my-case.spec.ts` (or create a new one):

Expand All @@ -57,7 +57,7 @@ Let's say you want to use your lately created `with-lodash` template with a `my-
// added test, using our new template
it('should pass with loadash', () => {
const testCase = configureTestCase('my-case', {template: 'with-lodash'});
const testCase = configureTestCase('my-case', { template: 'with-lodash'});
expect(testCase.run().status).toBe(0);
})
})
Expand Down
9 changes: 9 additions & 0 deletions e2e/__templates__/default/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module.exports = {
transform: {
'^.+\\.tsx?$': 'ts-jest',
},
testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.[jt]sx?$',
moduleFileExtensions: ['ts', 'js'],
testEnvironment: 'node',
globals: { 'ts-jest': { tsConfig: {} } },
};
2 changes: 1 addition & 1 deletion e2e/__templates__/default/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion e2e/__templates__/default/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ts-jest-e2e-tmpl-default",
"version": "0.0.0-test.0",
"version": "0.0.0-tmpl.0",
"private": true,
"devDependencies": {
"jest": "^23.4.2",
Expand Down
Loading

0 comments on commit 9343c7d

Please sign in to comment.