Skip to content

Commit 6db7a6b

Browse files
authored
Separate Functional and Unit Test Modes (#166)
* Update for seperate unit and functional test builds * Continue to support depracated test mode and add unit tests * Fix up unit tests * README updates * Fix up files for eject * Limit test mode to single bundle too * Change bundle and asset to all for the unit and functional modes
1 parent 475a18d commit 6db7a6b

File tree

9 files changed

+221
-104
lines changed

9 files changed

+221
-104
lines changed

README.md

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ There are three modes available to build a Dojo application, `dist`, `dev` and `
3939
dojo build app --mode dist
4040
```
4141

42-
The built application files are written to the `output/{mode selected}` directory
42+
The built application files are written to the `output/{dist/dev}` directory. The built test files are written to the `output/test/{unit|functionl}` directory.
4343

4444
Note: `dist` is the default mode and so can be run without any arguments, `dojo build app`.
4545

@@ -51,9 +51,13 @@ The `dist` mode creates a production-ready build.
5151

5252
The `dev` mode creates an application build that has been optimized for debugging and development.
5353

54-
#### Test mode
54+
#### Unit mode
5555

56-
The `test` mode creates bundles that can be used to run the unit and functional tests of the application.
56+
The `unit` mode creates bundles that can be used to run the unit tests of the application.
57+
58+
#### Functional mode
59+
60+
The `functional` mode creates bundles that can be used to run the functional tests of the application.
5761

5862
### Serving the Application
5963

@@ -126,14 +130,16 @@ Ejecting `@dojo/cli-build-app` will produce the following files under the `confi
126130
- `build-options.json`: the build-specific config options removed from the `.dojorc`
127131
- `ejected.config.js`: the root webpack config that passes the build options to the appropriate mode-specific config based on the `--env.mode` flag's value.
128132
- `base.config.js`: a common configuration used by the mode-specific configs.
133+
- `base.test.config.js`: a common configuration used by the unit and functional modes.
129134
- `dev.config.js`: the configuration used during development.
130135
- `dist.config.js`: the production configuration.
131-
- `test.config.js`: the configuration used when running tests.
136+
- `unit.config.js`: the configuration used when running unit tests.
137+
- `functional.config.js`: the configuration used when running functional tests.
132138

133139
As already noted, the dojorc's `build-app` options are moved to `config/build-app/build-options.json` after ejecting. Further, the modes are specified using webpack's `env` flag (e.g., `--env.mode=dev`), defaulting to `dist`. You can run a build using webpack with:
134140

135141
```bash
136-
node_modules/.bin/webpack --config=config/build-app/ejected.config.js --env.mode={dev|dist|test}
142+
node_modules/.bin/webpack --config=config/build-app/ejected.config.js --env.mode={dev|dist|unit|functional}
137143
```
138144

139145
### Configuration

src/base.config.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,14 +152,16 @@ export default function webpackConfigFactory(args: any): WebpackConfiguration {
152152
},
153153
[] as string[]
154154
);
155+
const singleBundle =
156+
args.singleBundle || args.mode === 'unit' || args.mode === 'functional' || args.mode === 'test';
155157

156158
const customTransformers: any[] = [];
157159

158-
if (lazyModules.length > 0 && !args.singleBundle) {
160+
if (lazyModules.length > 0 && !singleBundle) {
159161
customTransformers.push(registryTransformer(basePath, lazyModules));
160162
}
161163

162-
if (!args.legacy && !args.singleBundle) {
164+
if (!args.legacy && !singleBundle) {
163165
customTransformers.push(importTransformer(basePath, args.bundles));
164166
}
165167

@@ -276,7 +278,7 @@ export default function webpackConfigFactory(args: any): WebpackConfiguration {
276278
devtool: 'source-map',
277279
watchOptions: { ignored: /node_modules/ },
278280
plugins: removeEmpty([
279-
args.singleBundle &&
281+
singleBundle &&
280282
new webpack.optimize.LimitChunkCountPlugin({
281283
maxChunks: 1
282284
}),

src/test.config.ts renamed to src/base.test.config.ts

Lines changed: 4 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,10 @@
11
import baseConfigFactory from './base.config';
2-
import * as path from 'path';
3-
import * as webpack from 'webpack';
4-
import * as globby from 'globby';
5-
import * as CleanWebpackPlugin from 'clean-webpack-plugin';
2+
import { WebpackConfiguration } from './interfaces';
63
import * as ExtractTextPlugin from 'extract-text-webpack-plugin';
74

8-
const basePath = process.cwd();
9-
10-
function webpackConfig(args: any): webpack.Configuration {
5+
function webpackConfig(args: any): WebpackConfiguration {
116
const config = baseConfigFactory(args);
12-
const { plugins, output, module } = config;
13-
config.entry = () => {
14-
const unit = globby
15-
.sync([`${basePath}/tests/unit/**/*.ts`])
16-
.map((filename: string) => filename.replace(/\.ts$/, ''));
17-
18-
const functional = globby
19-
.sync([`${basePath}/tests/functional/**/*.ts`])
20-
.map((filename: string) => filename.replace(/\.ts$/, ''));
21-
22-
const tests: any = {};
23-
24-
if (unit.length) {
25-
tests.unit = unit;
26-
}
27-
28-
if (functional.length) {
29-
tests.functional = functional;
30-
}
31-
32-
return tests;
33-
};
7+
const { plugins, module } = config;
348
const externals: any[] = (config.externals as any[]) || [];
359

3610
const instrumenterOptions = args.legacy ? {} : { esModules: true };
@@ -41,8 +15,7 @@ function webpackConfig(args: any): webpack.Configuration {
4115
(plugin as any).options = { ...(plugin as any).options, disable: true };
4216
}
4317
return plugin;
44-
}),
45-
new CleanWebpackPlugin(['test'], { root: output.path, verbose: false })
18+
})
4619
];
4720

4821
module.rules = module.rules.map((rule) => {
@@ -74,10 +47,6 @@ function webpackConfig(args: any): webpack.Configuration {
7447
externals.push(/^intern/);
7548
config.externals = externals;
7649
config.devtool = 'inline-source-map';
77-
config.output = {
78-
...output,
79-
path: path.join(output.path, 'test')
80-
};
8150
return config;
8251
}
8352

src/ejected.config.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ import * as webpack from 'webpack';
22

33
import devConfigFactory from './dev.config';
44
import distConfigFactory from './dist.config';
5-
import testConfigFactory from './test.config';
5+
import unitConfigFactory from './unit.config';
6+
import functionalConfigFactory from './functional.config';
67

78
export interface EnvOptions {
8-
mode?: 'dev' | 'dist' | 'test';
9+
mode?: 'dev' | 'dist' | 'unit' | 'functional';
910
}
1011

1112
function webpackConfig(env: EnvOptions = {}): webpack.Configuration {
@@ -14,8 +15,10 @@ function webpackConfig(env: EnvOptions = {}): webpack.Configuration {
1415
let config: webpack.Configuration;
1516
if (mode === 'dev') {
1617
config = devConfigFactory(rc);
17-
} else if (mode === 'test') {
18-
config = testConfigFactory(rc);
18+
} else if (mode === 'unit') {
19+
config = unitConfigFactory(rc);
20+
} else if (mode === 'functional') {
21+
config = functionalConfigFactory(rc);
1922
} else {
2023
config = distConfigFactory(rc);
2124
}

src/functional.config.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import baseTestConfigFactory from './base.test.config';
2+
import * as path from 'path';
3+
import { WebpackConfiguration } from './interfaces';
4+
import * as globby from 'globby';
5+
import * as CleanWebpackPlugin from 'clean-webpack-plugin';
6+
7+
const basePath = process.cwd();
8+
9+
function webpackConfig(args: any): WebpackConfiguration {
10+
const config = baseTestConfigFactory(args);
11+
const { output, plugins } = config;
12+
config.entry = () => {
13+
const functional = globby
14+
.sync([`${basePath}/tests/functional/**/*.ts`])
15+
.map((filename: string) => filename.replace(/\.ts$/, ''));
16+
17+
const tests: any = {};
18+
19+
if (functional.length) {
20+
tests.all = functional;
21+
}
22+
23+
return tests;
24+
};
25+
config.plugins = [
26+
...plugins,
27+
new CleanWebpackPlugin(['functional'], { root: path.join(output.path, 'test'), verbose: false })
28+
];
29+
config.output = {
30+
...output,
31+
path: path.join(output.path, 'test', 'functional')
32+
};
33+
return config;
34+
}
35+
36+
export default webpackConfig;

src/main.ts

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ import * as history from 'connect-history-api-fallback';
1212

1313
const pkgDir = require('pkg-dir');
1414
import devConfigFactory from './dev.config';
15-
import testConfigFactory from './test.config';
15+
import unitConfigFactory from './unit.config';
16+
import functionalConfigFactory from './functional.config';
1617
import distConfigFactory from './dist.config';
1718
import logger from './logger';
1819
import { moveBuildOptions } from './util/eject';
@@ -21,6 +22,8 @@ const fixMultipleWatchTrigger = require('webpack-mild-compile');
2122
const hotMiddleware = require('webpack-hot-middleware');
2223
const webpackMiddleware = require('webpack-dev-middleware');
2324

25+
const testModes = ['test', 'unit', 'functional'];
26+
2427
function createCompiler(config: webpack.Configuration) {
2528
const compiler = webpack(config);
2629
fixMultipleWatchTrigger(compiler);
@@ -57,6 +60,11 @@ function build(config: webpack.Configuration, args: any) {
5760
return;
5861
}
5962
}
63+
if (args.mode === 'test') {
64+
console.warn(
65+
'Using `--mode=test` is deprecated and has only built the unit test bundle. This mode will be removed in the next major release, please use `unit` or `functional` explicitly instead.'
66+
);
67+
}
6068
resolve(args.serve || process.exit(0));
6169
});
6270
});
@@ -214,7 +222,7 @@ const command: Command = {
214222
describe: 'the output mode',
215223
alias: 'm',
216224
default: 'dist',
217-
choices: ['dist', 'dev', 'test']
225+
choices: ['dist', 'dev', 'test', 'unit', 'functional']
218226
});
219227

220228
options('watch', {
@@ -275,15 +283,17 @@ const command: Command = {
275283
remainingArgs = { ...remainingArgs, features: { ...remainingArgs.features, ...feature } };
276284
if (args.mode === 'dev') {
277285
config = devConfigFactory(remainingArgs);
278-
} else if (args.mode === 'test') {
279-
config = testConfigFactory(remainingArgs);
286+
} else if (args.mode === 'unit' || args.mode === 'test') {
287+
config = unitConfigFactory(remainingArgs);
288+
} else if (args.mode === 'functional') {
289+
config = functionalConfigFactory(remainingArgs);
280290
} else {
281291
config = distConfigFactory(remainingArgs);
282292
}
283293

284294
if (args.serve) {
285-
if (args.mode === 'test') {
286-
return Promise.reject(new Error('Cannot use `--serve` with `--mode=test`'));
295+
if (testModes.indexOf(args.mode) !== -1) {
296+
return Promise.reject(new Error(`Cannot use \`--serve\` with \`--mode=${args.mode}\``));
287297
}
288298
return serve(config, args);
289299
}
@@ -304,15 +314,17 @@ const command: Command = {
304314
files: [
305315
moveBuildOptions(`${this.group}-${this.name}`),
306316
'./base.config.js',
317+
'./base.test.config.js',
307318
'./dev.config.js',
308319
'./dist.config.js',
309320
'./ejected.config.js',
310-
'./test.config.js'
321+
'./unit.config.js',
322+
'./functional.config.js'
311323
]
312324
},
313325
hints: [
314326
`to build run ${chalk.underline(
315-
'./node_modules/.bin/webpack --config ./config/build-app/ejected.config.js --env.mode={dev|dist|test}'
327+
'./node_modules/.bin/webpack --config ./config/build-app/ejected.config.js --env.mode={dev|dist|unit|functional}'
316328
)}`
317329
],
318330
npm: {

src/unit.config.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import baseTestConfigFactory from './base.test.config';
2+
import * as path from 'path';
3+
import * as globby from 'globby';
4+
import * as CleanWebpackPlugin from 'clean-webpack-plugin';
5+
import { WebpackConfiguration } from './interfaces';
6+
7+
const basePath = process.cwd();
8+
9+
function webpackConfig(args: any): WebpackConfiguration {
10+
const config = baseTestConfigFactory(args);
11+
const { output, plugins } = config;
12+
config.entry = () => {
13+
const unit = globby
14+
.sync([`${basePath}/tests/unit/**/*.ts`])
15+
.map((filename: string) => filename.replace(/\.ts$/, ''));
16+
17+
const tests: any = {};
18+
19+
if (unit.length) {
20+
tests.all = unit;
21+
}
22+
23+
return tests;
24+
};
25+
config.plugins = [
26+
...plugins,
27+
new CleanWebpackPlugin(['unit'], { root: path.join(output.path, 'test'), verbose: false })
28+
];
29+
config.output = {
30+
...output,
31+
path: path.join(output.path, 'test', 'unit')
32+
};
33+
return config;
34+
}
35+
36+
export default webpackConfig;

tests/unit/ejected.config.ts

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,21 @@ const configJson: any = { bundles: {} };
77
let mockModule: MockModule;
88
let mockDevConfig: any;
99
let mockDistConfig: any;
10-
let mockTestConfig: any;
10+
let mockUnitTestConfig: any;
11+
let mockFunctionalTestConfig: any;
1112

1213
describe('ejected config', () => {
1314
beforeEach(() => {
1415
mockModule = new MockModule('../../src/ejected.config', require);
15-
mockModule.dependencies(['./dev.config', './dist.config', './test.config', './build-options.json']);
16+
mockModule.dependencies([
17+
'./dev.config',
18+
'./dist.config',
19+
'./unit.config',
20+
'./functional.config',
21+
'./build-options.json'
22+
]);
1623

17-
const configs = ['dev', 'dist', 'test'].map((name) => {
24+
const configs = ['dev', 'dist', 'unit', 'functional'].map((name) => {
1825
const config = mockModule.getMock(`./${name}.config`);
1926
config.default = stub();
2027
return config.default;
@@ -23,7 +30,8 @@ describe('ejected config', () => {
2330
Object.assign(mockModule.getMock('./build-options.json'), configJson);
2431
mockDevConfig = configs[0];
2532
mockDistConfig = configs[1];
26-
mockTestConfig = configs[2];
33+
mockUnitTestConfig = configs[2];
34+
mockFunctionalTestConfig = configs[3];
2735
});
2836

2937
afterEach(() => {
@@ -44,10 +52,17 @@ describe('ejected config', () => {
4452
assert.isTrue(mockDistConfig.calledWith(configJson));
4553
});
4654

47-
it('can run test mode', () => {
55+
it('can run unit mode', () => {
4856
const config = mockModule.getModuleUnderTest();
49-
config({ mode: 'test' });
50-
assert.isTrue(mockTestConfig.calledOnce);
51-
assert.isTrue(mockTestConfig.calledWith(configJson));
57+
config({ mode: 'unit' });
58+
assert.isTrue(mockUnitTestConfig.calledOnce);
59+
assert.isTrue(mockUnitTestConfig.calledWith(configJson));
60+
});
61+
62+
it('can run functional mode', () => {
63+
const config = mockModule.getModuleUnderTest();
64+
config({ mode: 'functional' });
65+
assert.isTrue(mockFunctionalTestConfig.calledOnce);
66+
assert.isTrue(mockFunctionalTestConfig.calledWith(configJson));
5267
});
5368
});

0 commit comments

Comments
 (0)