diff --git a/docs/api-builders/jest.md b/docs/api-builders/jest.md index f2388b5b44ec0..adf7eb304adfd 100644 --- a/docs/api-builders/jest.md +++ b/docs/api-builders/jest.md @@ -6,33 +6,49 @@ Run Jest unit tests ### bail -Type: `boolean` +Alias(es): b + +Type: `number` -Exit the test suite immediately upon the first failing test suite. (https://jestjs.io/docs/en/cli#bail) +Exit the test suite immediately after `n` number of failing tests. (https://jestjs.io/docs/en/cli#bail) ### ci Type: `boolean` -Fail on missing snapshots. (https://jestjs.io/docs/en/cli#ci) +Whether to run Jest in continuous integration (CI) mode. This option is on by default in most popular CI environments. It will prevent snapshots from being written unless explicitly requested. (https://jestjs.io/docs/en/cli#ci) ### codeCoverage Type: `boolean` -Export a code coverage report. (https://jestjs.io/docs/en/cli#coverage) +Indicates that test coverage information should be collected and reported in the output. (https://jestjs.io/docs/en/cli#coverage) + +### color + +Type: `boolean` + +Forces test results output color highlighting (even if stdout is not a TTY). Set to false if you would like to have no colors. (https://jestjs.io/docs/en/cli#colors) ### jestConfig Type: `string` -The path of the Jest configuration. (https://jestjs.io/docs/en/configuration.html) +The path of the Jest configuration. (https://jestjs.io/docs/en/configuration) + +### json + +Type: `boolean` + +Prints the test results in JSON. This mode will send all other test output and user messages to stderr. (https://jestjs.io/docs/en/cli#json) ### maxWorkers +Alias(es): w + Type: `number` -Max number of workers to run tests across. Useful for CI. (https://jestjs.io/docs/en/cli.html#maxworkers-num) +Specifies the maximum number of workers the worker-pool will spawn for running tests. This defaults to the number of the cores available on your machine. Useful for CI. (its usually best not to override this default) (https://jestjs.io/docs/en/cli#maxworkers-num) ### onlyChanged @@ -40,25 +56,33 @@ Alias(es): o Type: `boolean` -Isolate tests affected by uncommitted changes. (https://jestjs.io/docs/en/cli#onlychanged) +Attempts to identify which tests to run based on which files have changed in the current repository. Only works if you're running tests in a git or hg repository at the moment. (https://jestjs.io/docs/en/cli#onlychanged) + +### outputFile + +Type: `string` + +Write test results to a file when the --json option is also specified. (https://jestjs.io/docs/en/cli#outputfile-filename) ### passWithNoTests Type: `boolean` -Allow test suite to pass when no test files are found. (https://jestjs.io/docs/en/cli#passwithnotests) +Will not fail if no tests are found (for example while using `--testPathPattern`.) (https://jestjs.io/docs/en/cli#passwithnotests) ### runInBand +Alias(es): i + Type: `boolean` -Run tests in a single process as opposed to multiple workers. Useful for CI. (https://jestjs.io/docs/en/cli.html#runinband) +Run all tests serially in the current process (rather than creating a worker pool of child processes that run tests). This is sometimes useful for debugging, but such use cases are pretty rare. Useful for CI. (https://jestjs.io/docs/en/cli#runinband) ### setupFile Type: `string` -The name of a setup file used by Jest. (https://jestjs.io/docs/en/configuration.html#setuptestframeworkscriptfile-string) +The name of a setup file used by Jest. (https://jestjs.io/docs/en/configuration#setupfilesafterenv-array) ### silent @@ -66,13 +90,19 @@ Type: `boolean` Prevent tests from printing messages through the console. (https://jestjs.io/docs/en/cli#silent) +### testFile + +Type: `string` + +The name of the file to test. + ### testNamePattern Alias(es): t Type: `string` -Run only tests with a name that matches the regex. (https://jestjs.io/docs/en/cli.html#testnamepattern-regex) +Run only tests with a name that matches the regex pattern. (https://jestjs.io/docs/en/cli#testnamepattern-regex) ### tsConfig @@ -86,12 +116,22 @@ Alias(es): u Type: `boolean` -Re-record all failing snapshots. (https://jestjs.io/docs/en/cli#updatesnapshot) +Use this flag to re-record snapshots. Can be used together with a test suite pattern or with `--testNamePattern` to re-record snapshot for test matching the pattern. (https://jestjs.io/docs/en/cli#updatesnapshot) + +### useStderr + +Type: `boolean` + +Divert all output to stderr. ### watch -Default: `false` +Type: `boolean` + +Watch files for changes and rerun tests related to changed files. If you want to re-run all tests when a file has changed, use the `--watchAll` option. (https://jestjs.io/docs/en/cli#watch) + +### watchAll Type: `boolean` -Run tests when files change. (https://jestjs.io/docs/en/cli#watch) +Watch files for changes and rerun all tests when something changes. If you want to re-run only the tests that depend on the changed files, use the `--watch` option. (https://jestjs.io/docs/en/cli#watchall) diff --git a/packages/builders/src/jest/jest.builder.spec.ts b/packages/builders/src/jest/jest.builder.spec.ts index 0dd87649b9d6e..6b2381070aeeb 100644 --- a/packages/builders/src/jest/jest.builder.spec.ts +++ b/packages/builders/src/jest/jest.builder.spec.ts @@ -1,5 +1,6 @@ import JestBuilder from './jest.builder'; import { normalize } from '@angular-devkit/core'; +import { TestLogger } from '@angular-devkit/architect/testing'; jest.mock('jest'); const { runCLI } = require('jest'); import * as path from 'path'; @@ -8,7 +9,14 @@ describe('Jest Builder', () => { let builder: JestBuilder; beforeEach(() => { - builder = new JestBuilder(); + builder = new JestBuilder({ + host: {}, + logger: new TestLogger('test'), + workspace: { + root: '/root' + }, + architect: {} + }); runCLI.mockReturnValue( Promise.resolve({ results: { @@ -36,10 +44,7 @@ describe('Jest Builder', () => { { globals: JSON.stringify({ 'ts-jest': { - tsConfig: path.join( - '', - path.relative(root, './tsconfig.test.json') - ), + tsConfig: '/root/tsconfig.test.json', stringifyContentPathRegex: '\\.html$', astTransformers: [ 'jest-preset-angular/InlineHtmlStripStylesTransformer' @@ -48,7 +53,47 @@ describe('Jest Builder', () => { }), watch: false }, - ['./jest.config.js'] + ['/root/jest.config.js'] + ); + }); + + it('should send appropriate options to jestCLI when testFile is specified', () => { + const root = normalize('/root'); + + builder + .run({ + root, + builder: '', + projectType: 'application', + options: { + testFile: 'lib.spec.ts', + jestConfig: './jest.config.js', + tsConfig: './tsconfig.test.json', + codeCoverage: false, + runInBand: true, + testNamePattern: 'should load', + watch: false + } + }) + .toPromise(); + expect(runCLI).toHaveBeenCalledWith( + { + _: ['lib.spec.ts'], + globals: JSON.stringify({ + 'ts-jest': { + tsConfig: '/root/tsconfig.test.json', + stringifyContentPathRegex: '\\.html$', + astTransformers: [ + 'jest-preset-angular/InlineHtmlStripStylesTransformer' + ] + } + }), + coverage: false, + runInBand: true, + testNamePattern: 'should load', + watch: false + }, + ['/root/jest.config.js'] ); }); @@ -62,17 +107,21 @@ describe('Jest Builder', () => { options: { jestConfig: './jest.config.js', tsConfig: './tsconfig.test.json', - watch: false, codeCoverage: true, + bail: true, + color: false, ci: true, - updateSnapshot: true, + json: true, + maxWorkers: 2, onlyChanged: true, + outputFile: 'abc.txt', passWithNoTests: true, - bail: true, silent: true, - runInBand: true, - maxWorkers: 2, - testNamePattern: 'test' + testNamePattern: 'test', + updateSnapshot: true, + useStderr: true, + watch: false, + watchAll: false } }) .toPromise(); @@ -80,29 +129,30 @@ describe('Jest Builder', () => { { globals: JSON.stringify({ 'ts-jest': { - tsConfig: path.join( - '', - path.relative(root, './tsconfig.test.json') - ), + tsConfig: '/root/tsconfig.test.json', stringifyContentPathRegex: '\\.html$', astTransformers: [ 'jest-preset-angular/InlineHtmlStripStylesTransformer' ] } }), - watch: false, coverage: true, + bail: true, + color: false, ci: true, - updateSnapshot: true, + json: true, + maxWorkers: 2, onlyChanged: true, + outputFile: 'abc.txt', passWithNoTests: true, - bail: true, silent: true, - runInBand: true, - maxWorkers: 2, - testNamePattern: 'test' + testNamePattern: 'test', + updateSnapshot: true, + useStderr: true, + watch: false, + watchAll: false }, - ['./jest.config.js'] + ['/root/jest.config.js'] ); }); @@ -125,10 +175,7 @@ describe('Jest Builder', () => { { globals: JSON.stringify({ 'ts-jest': { - tsConfig: path.join( - '', - path.relative(root, './tsconfig.test.json') - ), + tsConfig: '/root/tsconfig.test.json', stringifyContentPathRegex: '\\.html$', astTransformers: [ 'jest-preset-angular/InlineHtmlStripStylesTransformer' @@ -141,7 +188,7 @@ describe('Jest Builder', () => { ), watch: false }, - ['./jest.config.js'] + ['/root/jest.config.js'] ); }); diff --git a/packages/builders/src/jest/jest.builder.ts b/packages/builders/src/jest/jest.builder.ts index c1a9757b08fa7..823d7867bef38 100644 --- a/packages/builders/src/jest/jest.builder.ts +++ b/packages/builders/src/jest/jest.builder.ts @@ -1,11 +1,11 @@ import { Builder, - BuildEvent, BuilderConfiguration, + BuildEvent, BuilderContext } from '@angular-devkit/architect'; -import { Observable, from } from 'rxjs'; +import { from, Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import * as path from 'path'; @@ -17,32 +17,42 @@ try { const { runCLI } = require('jest'); export interface JestBuilderOptions { + codeCoverage?: boolean; jestConfig: string; + testFile?: string; + setupFile?: string; tsConfig: string; - watch: boolean; - bail?: boolean; + bail?: number | boolean; ci?: boolean; - codeCoverage?: boolean; - onlyChanged?: boolean; + color?: boolean; + json?: boolean; maxWorkers?: number; + onlyChanged?: boolean; + outputFile?: string; passWithNoTests?: boolean; runInBand?: boolean; - setupFile?: string; silent?: boolean; - updateSnapshot?: boolean; testNamePattern?: string; + updateSnapshot?: boolean; + useStderr?: boolean; + watch?: boolean; + watchAll?: boolean; } export default class JestBuilder implements Builder { + constructor(private context: BuilderContext) {} run( builderConfig: BuilderConfiguration ): Observable { const options = builderConfig.options; + + options.jestConfig = path.resolve( + this.context.workspace.root, + options.jestConfig + ); + const tsJestConfig = { - tsConfig: path.join( - '', - path.relative(builderConfig.root, options.tsConfig) - ) + tsConfig: path.resolve(this.context.workspace.root, options.tsConfig) }; // TODO: This is hacky, We should probably just configure it in the user's workspace @@ -56,29 +66,29 @@ export default class JestBuilder implements Builder { ] }); } catch (e) {} + const config: any = { - watch: options.watch, coverage: options.codeCoverage, bail: options.bail, ci: options.ci, - updateSnapshot: options.updateSnapshot, + color: options.color, + json: options.json, + maxWorkers: options.maxWorkers, onlyChanged: options.onlyChanged, + outputFile: options.outputFile, passWithNoTests: options.passWithNoTests, - silent: options.silent, runInBand: options.runInBand, + silent: options.silent, + testNamePattern: options.testNamePattern, + updateSnapshot: options.updateSnapshot, + useStderr: options.useStderr, + watch: options.watch, + watchAll: options.watchAll, globals: JSON.stringify({ 'ts-jest': tsJestConfig }) }; - if (options.maxWorkers) { - config.maxWorkers = options.maxWorkers; - } - - if (options.testNamePattern) { - config.testNamePattern = options.testNamePattern; - } - if (options.setupFile) { config.setupTestFrameworkScriptFile = path.join( '', @@ -86,6 +96,10 @@ export default class JestBuilder implements Builder { ); } + if (options.testFile) { + config._ = [options.testFile]; + } + return from(runCLI(config, [options.jestConfig])).pipe( map((results: any) => { return { diff --git a/packages/builders/src/jest/schema.json b/packages/builders/src/jest/schema.json index ee57633e3e434..217bba24b077a 100644 --- a/packages/builders/src/jest/schema.json +++ b/packages/builders/src/jest/schema.json @@ -3,65 +3,91 @@ "description": "Jest target options for Build Facade", "type": "object", "properties": { + "codeCoverage": { + "description": "Indicates that test coverage information should be collected and reported in the output. (https://jestjs.io/docs/en/cli#coverage)", + "type": "boolean" + }, "jestConfig": { - "type": "string", - "description": "The path of the Jest configuration. (https://jestjs.io/docs/en/configuration.html)" + "description": "The path of the Jest configuration. (https://jestjs.io/docs/en/configuration)", + "type": "string" + }, + "testFile": { + "description": "The name of the file to test.", + "type": "string" }, "tsConfig": { - "type": "string", - "description": "The name of the Typescript configuration file." + "description": "The name of the Typescript configuration file.", + "type": "string" }, "setupFile": { - "type": "string", - "description": "The name of a setup file used by Jest. (https://jestjs.io/docs/en/configuration.html#setuptestframeworkscriptfile-string)" + "description": "The name of a setup file used by Jest. (https://jestjs.io/docs/en/configuration#setupfilesafterenv-array)", + "type": "string" }, - "watch": { - "type": "boolean", - "description": "Run tests when files change. (https://jestjs.io/docs/en/cli#watch)", - "default": false + "bail": { + "alias": "b", + "description": "Exit the test suite immediately after `n` number of failing tests. (https://jestjs.io/docs/en/cli#bail)", + "type": ["number", "boolean"] }, - "onlyChanged": { - "type": "boolean", - "alias": "o", - "description": "Isolate tests affected by uncommitted changes. (https://jestjs.io/docs/en/cli#onlychanged)" + "ci": { + "description": "Whether to run Jest in continuous integration (CI) mode. This option is on by default in most popular CI environments. It will prevent snapshots from being written unless explicitly requested. (https://jestjs.io/docs/en/cli#ci)", + "type": "boolean" }, - "passWithNoTests": { - "type": "boolean", - "description": "Allow test suite to pass when no test files are found. (https://jestjs.io/docs/en/cli#passwithnotests)" + "color": { + "description": "Forces test results output color highlighting (even if stdout is not a TTY). Set to false if you would like to have no colors. (https://jestjs.io/docs/en/cli#colors)", + "type": "boolean" }, - "codeCoverage": { - "type": "boolean", - "description": "Export a code coverage report. (https://jestjs.io/docs/en/cli#coverage)" + "json": { + "description": "Prints the test results in JSON. This mode will send all other test output and user messages to stderr. (https://jestjs.io/docs/en/cli#json)", + "type": "boolean" }, - "updateSnapshot": { - "type": "boolean", - "alias": "u", - "description": "Re-record all failing snapshots. (https://jestjs.io/docs/en/cli#updatesnapshot)" + "maxWorkers": { + "alias": "w", + "description": "Specifies the maximum number of workers the worker-pool will spawn for running tests. This defaults to the number of the cores available on your machine. Useful for CI. (its usually best not to override this default) (https://jestjs.io/docs/en/cli#maxworkers-num)", + "type": "number" }, - "ci": { - "type": "boolean", - "description": "Fail on missing snapshots. (https://jestjs.io/docs/en/cli#ci)" + "onlyChanged": { + "alias": "o", + "description": "Attempts to identify which tests to run based on which files have changed in the current repository. Only works if you're running tests in a git or hg repository at the moment. (https://jestjs.io/docs/en/cli#onlychanged)", + "type": "boolean" }, - "bail": { - "type": "boolean", - "description": "Exit the test suite immediately upon the first failing test suite. (https://jestjs.io/docs/en/cli#bail)" + "outputFile": { + "description": "Write test results to a file when the --json option is also specified. (https://jestjs.io/docs/en/cli#outputfile-filename)", + "type": "string" }, - "silent": { - "type": "boolean", - "description": "Prevent tests from printing messages through the console. (https://jestjs.io/docs/en/cli#silent)" + "passWithNoTests": { + "description": "Will not fail if no tests are found (for example while using `--testPathPattern`.) (https://jestjs.io/docs/en/cli#passwithnotests)", + "type": "boolean" }, "runInBand": { - "type": "boolean", - "description": "Run tests in a single process as opposed to multiple workers. Useful for CI. (https://jestjs.io/docs/en/cli.html#runinband)" + "alias": "i", + "description": "Run all tests serially in the current process (rather than creating a worker pool of child processes that run tests). This is sometimes useful for debugging, but such use cases are pretty rare. Useful for CI. (https://jestjs.io/docs/en/cli#runinband)", + "type": "boolean" }, - "maxWorkers": { - "type": "number", - "description": "Max number of workers to run tests across. Useful for CI. (https://jestjs.io/docs/en/cli.html#maxworkers-num)" + "silent": { + "description": "Prevent tests from printing messages through the console. (https://jestjs.io/docs/en/cli#silent)", + "type": "boolean" }, "testNamePattern": { - "type": "string", "alias": "t", - "description": "Run only tests with a name that matches the regex. (https://jestjs.io/docs/en/cli.html#testnamepattern-regex)" + "description": "Run only tests with a name that matches the regex pattern. (https://jestjs.io/docs/en/cli#testnamepattern-regex)", + "type": "string" + }, + "updateSnapshot": { + "alias": "u", + "description": "Use this flag to re-record snapshots. Can be used together with a test suite pattern or with `--testNamePattern` to re-record snapshot for test matching the pattern. (https://jestjs.io/docs/en/cli#updatesnapshot)", + "type": "boolean" + }, + "useStderr": { + "description": "Divert all output to stderr.", + "type": "boolean" + }, + "watch": { + "description": "Watch files for changes and rerun tests related to changed files. If you want to re-run all tests when a file has changed, use the `--watchAll` option. (https://jestjs.io/docs/en/cli#watch)", + "type": "boolean" + }, + "watchAll": { + "description": "Watch files for changes and rerun all tests when something changes. If you want to re-run only the tests that depend on the changed files, use the `--watch` option. (https://jestjs.io/docs/en/cli#watchall)", + "type": "boolean" } }, "required": ["jestConfig", "tsConfig"]