Skip to content
This repository was archived by the owner on Dec 1, 2019. It is now read-only.

Commit 8cecd9e

Browse files
committed
test: output tests
1 parent a1029c7 commit 8cecd9e

12 files changed

+311
-153
lines changed

package.json

+5-5
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"homepage": "https://github.com/s-panferov/awesome-typescript-loader",
3434
"dependencies": {
3535
"colors": "^1.1.2",
36-
"enhanced-resolve": "^3.0.3",
36+
"enhanced-resolve": "^3.1.0",
3737
"loader-utils": "^0.2.16",
3838
"lodash": "^4.17.4",
3939
"object-assign": "^4.1.1",
@@ -42,9 +42,9 @@
4242
"devDependencies": {
4343
"@types/chai": "^3.4.34",
4444
"@types/colors": "^1.1.1",
45-
"@types/lodash": "^4.14.51",
46-
"@types/mocha": "^2.2.38",
47-
"@types/node": "^7.0.4",
45+
"@types/lodash": "^4.14.52",
46+
"@types/mocha": "^2.2.39",
47+
"@types/node": "^7.0.5",
4848
"@types/sinon": "^1.16.34",
4949
"bluebird": "^3.4.7",
5050
"chai": "^3.5.0",
@@ -58,6 +58,6 @@
5858
"temp": "^0.8.3",
5959
"tslint": "^4.4.2",
6060
"typescript": "^2.1.5",
61-
"webpack": "2.2.0"
61+
"webpack": "^2.2.1"
6262
}
6363
}

src/__test__/babel.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import {
22
src, webpackConfig, tsconfig, install,
3-
watch, checkOutput, expectErrors, query, run
3+
watch, checkOutput, expectErrors, query, spec
44
} from './utils';
55

6-
run(__filename, async function() {
6+
spec(__filename, async function() {
77
const index = src('index.ts', `
88
class HiThere {
99
constructor(a: number, b: string) {

src/__test__/compile-output.ts

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import {
2+
src, tsconfig, stdout, stderr,
3+
spec, file, exec
4+
} from './utils';
5+
6+
export function config(env) {
7+
file(`webpack.config.js`, `
8+
const path = require('path')
9+
module.exports = {
10+
entry: { index: path.join(process.cwd(), '${env.SRC_DIR}', 'index.ts') },
11+
output: {
12+
path: path.join(process.cwd(), '${env.OUT_DIR}'),
13+
filename: '[name].js'
14+
},
15+
resolve: {
16+
extensions: ['.ts', '.tsx', '.js', '.jsx'],
17+
},
18+
module: {
19+
loaders: [
20+
{
21+
test: /\.(tsx?|jsx?)/,
22+
loader: path.resolve(process.cwd(), '..', '..', 'index.js'),
23+
include: [ path.join(process.cwd(), '${env.SRC_DIR}') ],
24+
query: {
25+
silent: true
26+
}
27+
}
28+
]
29+
}
30+
}
31+
`);
32+
}
33+
34+
spec(__filename, async function(env, done) {
35+
src('index.ts', `
36+
export default function sum(a: number, b: number) {
37+
return a + b;
38+
}
39+
40+
sum(1, '1');
41+
`);
42+
43+
tsconfig();
44+
config(env);
45+
46+
const webpack = exec('webpack');
47+
48+
await webpack.wait(
49+
stderr('Checking finished with 1 errors'),
50+
stdout([
51+
'ERROR in [at-loader]',
52+
`Argument of type '"1"' is not assignable to parameter of type 'number'`
53+
])
54+
);
55+
56+
webpack.close();
57+
done();
58+
});
59+

src/__test__/declaration.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import {
22
src, webpackConfig, tsconfig,
3-
watch, checkOutput, expectErrors, run
3+
watch, checkOutput, expectErrors, spec
44
} from './utils';
55

6-
run(__filename, async function() {
6+
spec(__filename, async function() {
77
const index = src('index.ts', `
88
export { default as sum } from './utils/sum'
99
`);

src/__test__/error.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import {
22
src, webpackConfig, tsconfig,
3-
compile, checkOutput, expectErrors, run
3+
compile, checkOutput, expectErrors, spec
44
} from './utils';
55

6-
run(__filename, async function() {
6+
spec(__filename, async function() {
77
src('index.ts', `
88
function sum(a: number, b: number) {
99
return a + b;

src/__test__/react.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import {
22
src, webpackConfig, expectErrors,
3-
tsconfig, compile, install, entry, run
3+
tsconfig, compile, install, entry, spec
44
} from './utils';
55

6-
run(__filename, async function() {
6+
spec(__filename, async function() {
77
install(
88
'react',
99
'react-dom',

src/__test__/remove.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import {
22
src, webpackConfig, tsconfig,
3-
watch, expectErrors, xrun
3+
watch, expectErrors, xspec
44
} from './utils';
55

6-
xrun(__filename, async function() {
6+
xspec(__filename, async function() {
77
const index = src('index.ts', `
88
import sum from './sum'
99
import mul from './mul'

src/__test__/simple.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import {
22
src, webpackConfig, tsconfig,
3-
compile, checkOutput, expectErrors, run
3+
compile, checkOutput, expectErrors, spec
44
} from './utils';
55

6-
run(__filename, async function() {
6+
spec(__filename, async function() {
77
src('index.ts', `
88
class HiThere {
99
constructor(a: number, b: string) {

src/__test__/utils.ts

+157-8
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ export interface ConfigOptions {
3131
const TEST_DIR = path.join(process.cwd(), '.test');
3232
const SRC_DIR = './src';
3333
const OUT_DIR = './out';
34+
const WEBPACK = path.join(
35+
path.dirname(
36+
path.dirname(
37+
require.resolve('webpack'))), 'bin', 'webpack.js');
3438

3539
mkdirp.sync(TEST_DIR);
3640

@@ -80,6 +84,130 @@ export function webpackConfig(...enchance: any[]) {
8084
return config;
8185
}
8286

87+
export interface Output {
88+
type: 'stderr' | 'stdout';
89+
data: string;
90+
}
91+
92+
export type OutputMatcher = (o: Output) => boolean;
93+
94+
export class Exec {
95+
process: child.ChildProcess;
96+
watchers: {
97+
resolve: any,
98+
reject: any,
99+
matchers: OutputMatcher[],
100+
}[] = [];
101+
102+
close() {
103+
this.process.kill();
104+
}
105+
106+
invoke({stdout, stderr}) {
107+
this.watchers = this.watchers.filter(watcher => {
108+
const output: Output = {
109+
type: stdout ? 'stdout' : 'stderr',
110+
data: stdout || stderr
111+
};
112+
113+
const index = watcher.matchers.findIndex(m => m(output));
114+
115+
if (index === -1) {
116+
watcher.reject(new Error(`Unexpected ${output.type}:\n${output.data}`));
117+
return false;
118+
}
119+
120+
watcher.matchers.splice(index, 1);
121+
if (watcher.matchers.length === 0) {
122+
watcher.resolve();
123+
return false;
124+
} else {
125+
return true;
126+
}
127+
});
128+
}
129+
130+
wait(...matchers: OutputMatcher[]): Promise<any> {
131+
return new Promise((resolve, reject) => {
132+
const watcher = {
133+
resolve,
134+
reject,
135+
matchers,
136+
};
137+
138+
this.watchers.push(watcher);
139+
});
140+
}
141+
142+
alive(): Promise<any> {
143+
return new Promise((resolve, reject) => {
144+
this.process.on('exit', resolve);
145+
});
146+
}
147+
}
148+
149+
export type Test = string | (string | [boolean, string])[] | RegExp | ((str: string) => boolean);
150+
export function streamTest(stream = 'stdout', test: Test) {
151+
let matcher: (str: string) => boolean;
152+
153+
if (typeof test === 'string') {
154+
matcher = (o: string) => o.indexOf(test) !== -1;
155+
} else if (Array.isArray(test)) {
156+
matcher = (o: string) => test.every(test => {
157+
if (typeof test === 'string') {
158+
return o.indexOf(test) !== -1;
159+
} else {
160+
const [flag, str] = test;
161+
if (flag) {
162+
return o.indexOf(str) !== -1;
163+
} else {
164+
return o.indexOf(str) === -1;
165+
}
166+
}
167+
});
168+
} else if (test instanceof RegExp) {
169+
matcher => (o: string) => test.test(o);
170+
} else {
171+
matcher = test;
172+
}
173+
174+
return (o: Output) => (o.type === stream) && matcher(o.data);
175+
}
176+
177+
export const stdout = (test: Test) => streamTest('stdout', test);
178+
export const stderr = (test: Test) => streamTest('stderr', test);
179+
180+
export function exec(command: string, args?: string[], options?: child.SpawnOptions) {
181+
const p = child.spawn('node', [WEBPACK].concat(args), {
182+
shell: false,
183+
stdio: 'pipe',
184+
env: process.env
185+
});
186+
187+
const waiter = new Exec();
188+
189+
p.stdout.on('data', (data) => {
190+
console.log(data.toString());
191+
waiter.invoke({ stdout: data.toString(), stderr: null });
192+
});
193+
194+
p.stderr.on('data', (data) => {
195+
console.error(data.toString());
196+
waiter.invoke({ stdout: null, stderr: data.toString() });
197+
});
198+
199+
process.on('beforeExit', () => {
200+
p.kill();
201+
});
202+
203+
process.on('exit', () => {
204+
p.kill();
205+
});
206+
207+
waiter.process = p;
208+
return waiter;
209+
}
210+
83211
export function expectErrors(stats: any, count: number, errors: string[] = []) {
84212
stats.compilation.errors.every(err => {
85213
const str = err.toString();
@@ -109,7 +237,7 @@ export function json(obj) {
109237
export function checkOutput(fileName: string, fragment: string) {
110238
const source = readOutput(fileName);
111239

112-
if (!source) { process.exit() }
240+
if (!source) { process.exit(); }
113241

114242
expect(source.replace(/\s/g, '')).include(fragment.replace(/\s/g, ''));
115243
}
@@ -138,8 +266,16 @@ export function compile(config?): Promise<any> {
138266
});
139267
}
140268

141-
export function run<T>(name: string, cb: () => Promise<T>, disable = false) {
142-
const runner = () => {
269+
export interface TestEnv {
270+
TEST_DIR: string;
271+
OUT_DIR: string;
272+
SRC_DIR: string;
273+
LOADER: string;
274+
WEBPACK: string;
275+
}
276+
277+
export function spec<T>(name: string, cb: (env: TestEnv, done?: () => void) => Promise<T>, disable = false) {
278+
const runner = (done?) => {
143279
const temp = path.join(
144280
TEST_DIR,
145281
path.basename(name).replace('.', '') + '-' +
@@ -152,7 +288,16 @@ export function run<T>(name: string, cb: () => Promise<T>, disable = false) {
152288
let cwd = process.cwd();
153289
process.chdir(temp);
154290
pkg();
155-
const promise = cb();
291+
292+
const env = {
293+
TEST_DIR,
294+
OUT_DIR,
295+
SRC_DIR,
296+
LOADER,
297+
WEBPACK
298+
};
299+
300+
const promise = cb(env, done);
156301
return promise
157302
.then(a => {
158303
process.chdir(cwd);
@@ -164,15 +309,19 @@ export function run<T>(name: string, cb: () => Promise<T>, disable = false) {
164309
});
165310
};
166311

312+
const asyncRunner = cb.length === 2
313+
? (done) => { runner(done).catch(done); return; }
314+
: () => runner();
315+
167316
if (disable) {
168-
xit(name, runner);
317+
xit(name, asyncRunner);
169318
} else {
170-
it(name, runner);
319+
it(name, asyncRunner);
171320
}
172321
}
173322

174-
export function xrun<T>(name: string, cb: () => Promise<T>) {
175-
return run(name, cb, true);
323+
export function xspec<T>(name: string, cb: () => Promise<T>) {
324+
return spec(name, cb, true);
176325
}
177326

178327
export function watch(config, cb?: (err, stats) => void): Watch {

0 commit comments

Comments
 (0)