Skip to content

Commit 89df4ce

Browse files
fix: integrate Jest test runner
1 parent b6d6be3 commit 89df4ce

File tree

6 files changed

+279
-6
lines changed

6 files changed

+279
-6
lines changed

fuse.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { FuseBox, QuantumPlugin, JSONPlugin, RawPlugin, Sparky } from 'fuse-box'
1+
import { FuseBox, QuantumPlugin, JSONPlugin, RawPlugin } from 'fuse-box'
2+
import { src, task } from 'fuse-box/sparky'
23
import { resolve } from 'path'
34
import { argv } from 'yargs'
45
import shabang from './tools/scripts/fuse-shebang'
@@ -37,11 +38,15 @@ const fuseConfig = FuseBox.init({
3738

3839
const bundle = fuseConfig.bundle(appName)
3940

40-
Sparky.task('test', () => {
41+
task('test', () => {
4142
bundle.test('[spec/**/**.ts]', {})
4243
})
4344

44-
Sparky.task('bundle', () => {
45+
task('cp.jest', () => {
46+
return src('jest/**', { base: 'src/templates/unit-tests' }).dest('.build/')
47+
})
48+
49+
task('bundle', ['cp.jest'], () => {
4550
bundle.instructions('> [src/index.ts]')
4651
!isProdBuild &&
4752
bundle.watch(`src/**`).completed(fp => shabang(fp.bundle, absOutputPath))

src/commands/test.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,33 @@ command(
1313
test()
1414
}
1515
)
16-
console.log(resolve('preprocessor.js'))
16+
1717
function test() {
1818
logInfo('Testing....')
1919

2020
jest.runCLI(
2121
{
2222
transform: JSON.stringify({
23-
'^.+\\.(ts|js|html)$': resolve('testing/preprocessor.js')
23+
'^.+\\.(ts|js|html)$': resolve(
24+
'node_modules/fusing-angular-cli/.build/jest/preprocessor.js'
25+
)
2426
}),
2527
testMatch: [
2628
'**/__tests__/**/*.+(ts|js)?(x)',
2729
'**/+(*.)+(spec|test).+(ts|js)?(x)'
2830
],
2931
moduleFileExtensions: ['ts', 'js', 'html', 'json'],
30-
setupTestFrameworkScriptFile: '<rootDir>/testing/jest.setup.js'
32+
setupTestFrameworkScriptFile: resolve(
33+
'node_modules/fusing-angular-cli/.build/jest/jest.setup.js'
34+
),
35+
snapshotSerializers: [
36+
resolve(
37+
'node_modules/fusing-angular-cli/.build/jest/AngularSnapshotSerializer.js'
38+
),
39+
resolve(
40+
'node_modules/fusing-angular-cli/.build/jest/HTMLCommentSerializer.js'
41+
)
42+
]
3143
},
3244
[resolve(__dirname, '../../')]
3345
)
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
'use strict'
2+
3+
const printAttributes = (val, attributes, print, indent, colors, opts) => {
4+
return attributes
5+
.sort()
6+
.map(attribute => {
7+
return (
8+
opts.spacing +
9+
indent(colors.prop.open + attribute + colors.prop.close + '=') +
10+
colors.value.open +
11+
(val.componentInstance[attribute] &&
12+
val.componentInstance[attribute].constructor
13+
? '{[Function ' +
14+
val.componentInstance[attribute].constructor.name +
15+
']}'
16+
: `"${val.componentInstance[attribute]}"`) +
17+
colors.value.close
18+
)
19+
})
20+
.join('')
21+
}
22+
23+
const print = (val, print, indent, opts, colors) => {
24+
let result = ''
25+
let componentAttrs = ''
26+
27+
const componentName = val.componentRef._elDef.element.name
28+
const nodes = (val.componentRef._view.nodes || [])
29+
.filter(node => node && node.hasOwnProperty('renderElement'))
30+
.map(node =>
31+
Array.from(node.renderElement.childNodes)
32+
.map(print)
33+
.join('')
34+
)
35+
.join(opts.edgeSpacing)
36+
37+
const attributes = Object.keys(val.componentInstance)
38+
39+
if (attributes.length) {
40+
componentAttrs += printAttributes(
41+
val,
42+
attributes,
43+
print,
44+
indent,
45+
colors,
46+
opts
47+
)
48+
}
49+
50+
return (
51+
'<' +
52+
componentName +
53+
componentAttrs +
54+
(componentAttrs.length ? '\n' : '') +
55+
'>\n' +
56+
indent(nodes) +
57+
'\n</' +
58+
componentName +
59+
'>'
60+
)
61+
}
62+
63+
const test = val =>
64+
val !== undefined &&
65+
val !== null &&
66+
typeof val === 'object' &&
67+
Object.prototype.hasOwnProperty.call(val, 'componentRef')
68+
69+
module.exports = {
70+
print: print,
71+
test: test
72+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
3+
*
4+
* This source code is licensed under the BSD-style license found in the
5+
* LICENSE file in the root directory of this source tree. An additional grant
6+
* of patent rights can be found in the PATENTS file in the same directory.
7+
*
8+
*/
9+
10+
'use strict'
11+
12+
const HTML_ELEMENT_REGEXP = /Comment/
13+
const test = value =>
14+
value !== undefined &&
15+
value !== null &&
16+
value.nodeType === 8 &&
17+
value.constructor !== undefined &&
18+
HTML_ELEMENT_REGEXP.test(value.constructor.name)
19+
20+
const print = () => ''
21+
22+
module.exports = {
23+
print: print,
24+
test: test
25+
}
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
'use strict'
2+
3+
require('core-js/es6/reflect')
4+
require('core-js/es7/reflect')
5+
require('zone.js/dist/zone.js')
6+
require('zone.js/dist/proxy.js')
7+
require('zone.js/dist/sync-test')
8+
require('zone.js/dist/async-test')
9+
require('zone.js/dist/fake-async-test')
10+
11+
/**
12+
* Patch Jest's describe/test/beforeEach/afterEach functions so test code
13+
* always runs in a testZone (ProxyZone).
14+
*/
15+
16+
if (Zone === undefined) {
17+
throw new Error('Missing: Zone (zone.js)')
18+
}
19+
if (jest === undefined) {
20+
throw new Error(
21+
'Missing: jest.\n' +
22+
'This patch must be included in a script called with ' +
23+
'`setupTestFrameworkScriptFile` in Jest config.'
24+
)
25+
}
26+
if (jest['__zone_patch__'] === true) {
27+
throw new Error("'jest' has already been patched with 'Zone'.")
28+
}
29+
30+
jest['__zone_patch__'] = true
31+
const SyncTestZoneSpec = Zone['SyncTestZoneSpec']
32+
const ProxyZoneSpec = Zone['ProxyZoneSpec']
33+
34+
if (SyncTestZoneSpec === undefined) {
35+
throw new Error('Missing: SyncTestZoneSpec (zone.js/dist/sync-test)')
36+
}
37+
if (ProxyZoneSpec === undefined) {
38+
throw new Error('Missing: ProxyZoneSpec (zone.js/dist/proxy.js)')
39+
}
40+
41+
const env = global
42+
const ambientZone = Zone.current
43+
44+
// Create a synchronous-only zone in which to run `describe` blocks in order to
45+
// raise an error if any asynchronous operations are attempted
46+
// inside of a `describe` but outside of a `beforeEach` or `it`.
47+
const syncZone = ambientZone.fork(new SyncTestZoneSpec('jest.describe'))
48+
function wrapDescribeInZone(describeBody) {
49+
return () => syncZone.run(describeBody, null, arguments)
50+
}
51+
52+
// Create a proxy zone in which to run `test` blocks so that the tests function
53+
// can retroactively install different zones.
54+
const testProxyZone = ambientZone.fork(new ProxyZoneSpec())
55+
function wrapTestInZone(testBody) {
56+
if (testBody === undefined) {
57+
return
58+
}
59+
return testBody.length === 0
60+
? () => testProxyZone.run(testBody, null)
61+
: done => testProxyZone.run(testBody, null, [done])
62+
}
63+
64+
;['xdescribe', 'fdescribe', 'describe'].forEach(methodName => {
65+
const originaljestFn = env[methodName]
66+
env[methodName] = function(description, specDefinitions) {
67+
return originaljestFn.call(
68+
this,
69+
description,
70+
wrapDescribeInZone(specDefinitions)
71+
)
72+
}
73+
if (methodName === 'describe') {
74+
env[methodName].only = env['fdescribe']
75+
env[methodName].skip = env['xdescribe']
76+
}
77+
})
78+
79+
;['xit', 'fit', 'test', 'it'].forEach(methodName => {
80+
const originaljestFn = env[methodName]
81+
env[methodName] = function(description, specDefinitions, timeout) {
82+
arguments[1] = wrapTestInZone(specDefinitions)
83+
return originaljestFn.apply(this, arguments)
84+
}
85+
if (methodName === 'test' || methodName === 'it') {
86+
env[methodName].only = env['fit']
87+
env[methodName].skip = env['xit']
88+
}
89+
})
90+
91+
;['beforeEach', 'afterEach', 'beforeAll', 'afterAll'].forEach(methodName => {
92+
const originaljestFn = env[methodName]
93+
env[methodName] = function(specDefinitions, timeout) {
94+
arguments[0] = wrapTestInZone(specDefinitions)
95+
return originaljestFn.apply(this, arguments)
96+
}
97+
})
98+
99+
// const AngularSnapshotSerializer = require('./AngularSnapshotSerializer');
100+
// const HTMLCommentSerializer = require('./HTMLCommentSerializer');
101+
const getTestBed = require('@angular/core/testing').getTestBed
102+
const BrowserDynamicTestingModule = require('@angular/platform-browser-dynamic/testing')
103+
.BrowserDynamicTestingModule
104+
const platformBrowserDynamicTesting = require('@angular/platform-browser-dynamic/testing')
105+
.platformBrowserDynamicTesting
106+
107+
getTestBed().initTestEnvironment(
108+
BrowserDynamicTestingModule,
109+
platformBrowserDynamicTesting()
110+
)
111+
112+
const mock = () => {
113+
let storage = {}
114+
return {
115+
getItem: key => (key in storage ? storage[key] : null),
116+
setItem: (key, value) => (storage[key] = value || ''),
117+
removeItem: key => delete storage[key],
118+
clear: () => (storage = {})
119+
}
120+
}
121+
// Object.defineProperty(window, 'Hammer', { value: {} });
122+
Object.defineProperty(window, 'CSS', { value: mock() })
123+
Object.defineProperty(window, 'matchMedia', {
124+
value: jest.fn(() => ({ matches: true }))
125+
})
126+
Object.defineProperty(window, 'localStorage', { value: mock() })
127+
Object.defineProperty(window, 'sessionStorage', { value: mock() })
128+
Object.defineProperty(window, 'getComputedStyle', {
129+
value: () => {
130+
return {
131+
display: 'none',
132+
appearance: ['-webkit-appearance']
133+
}
134+
}
135+
})
136+
137+
// For Angular Material
138+
Object.defineProperty(document.body.style, 'transform', {
139+
value: () => {
140+
return {
141+
enumerable: true,
142+
configurable: true
143+
}
144+
}
145+
})
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
const process = require('ts-jest/preprocessor.js').process
2+
const TEMPLATE_URL_REGEX = /templateUrl\s*:\s*('|")(\.\/){0,}(.*)('|")/g
3+
const STYLE_URLS_REGEX = /styleUrls\s*:\s*\[[^\]]*\]/g
4+
const ESCAPE_TEMPLATE_REGEX = /(\${|\`)/g
5+
6+
module.exports.process = (src, path, config, transformOptions) => {
7+
if (path.endsWith('.html')) {
8+
src = src.replace(ESCAPE_TEMPLATE_REGEX, '\\$1')
9+
}
10+
src = src
11+
.replace(TEMPLATE_URL_REGEX, 'template: require($1./$3$4)')
12+
.replace(STYLE_URLS_REGEX, 'styles: []')
13+
return process(src, path, config, transformOptions)
14+
}

0 commit comments

Comments
 (0)