@@ -31,6 +31,10 @@ export interface ConfigOptions {
31
31
const TEST_DIR = path . join ( process . cwd ( ) , '.test' ) ;
32
32
const SRC_DIR = './src' ;
33
33
const OUT_DIR = './out' ;
34
+ const WEBPACK = path . join (
35
+ path . dirname (
36
+ path . dirname (
37
+ require . resolve ( 'webpack' ) ) ) , 'bin' , 'webpack.js' ) ;
34
38
35
39
mkdirp . sync ( TEST_DIR ) ;
36
40
@@ -80,6 +84,130 @@ export function webpackConfig(...enchance: any[]) {
80
84
return config ;
81
85
}
82
86
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
+
83
211
export function expectErrors ( stats : any , count : number , errors : string [ ] = [ ] ) {
84
212
stats . compilation . errors . every ( err => {
85
213
const str = err . toString ( ) ;
@@ -109,7 +237,7 @@ export function json(obj) {
109
237
export function checkOutput ( fileName : string , fragment : string ) {
110
238
const source = readOutput ( fileName ) ;
111
239
112
- if ( ! source ) { process . exit ( ) }
240
+ if ( ! source ) { process . exit ( ) ; }
113
241
114
242
expect ( source . replace ( / \s / g, '' ) ) . include ( fragment . replace ( / \s / g, '' ) ) ;
115
243
}
@@ -138,8 +266,16 @@ export function compile(config?): Promise<any> {
138
266
} ) ;
139
267
}
140
268
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 ?) => {
143
279
const temp = path . join (
144
280
TEST_DIR ,
145
281
path . basename ( name ) . replace ( '.' , '' ) + '-' +
@@ -152,7 +288,16 @@ export function run<T>(name: string, cb: () => Promise<T>, disable = false) {
152
288
let cwd = process . cwd ( ) ;
153
289
process . chdir ( temp ) ;
154
290
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 ) ;
156
301
return promise
157
302
. then ( a => {
158
303
process . chdir ( cwd ) ;
@@ -164,15 +309,19 @@ export function run<T>(name: string, cb: () => Promise<T>, disable = false) {
164
309
} ) ;
165
310
} ;
166
311
312
+ const asyncRunner = cb . length === 2
313
+ ? ( done ) => { runner ( done ) . catch ( done ) ; return ; }
314
+ : ( ) => runner ( ) ;
315
+
167
316
if ( disable ) {
168
- xit ( name , runner ) ;
317
+ xit ( name , asyncRunner ) ;
169
318
} else {
170
- it ( name , runner ) ;
319
+ it ( name , asyncRunner ) ;
171
320
}
172
321
}
173
322
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 ) ;
176
325
}
177
326
178
327
export function watch ( config , cb ?: ( err , stats ) => void ) : Watch {
0 commit comments