/
js-api-spec.ts
142 lines (128 loc) · 4.09 KB
/
js-api-spec.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/* eslint-disable no-process-exit */
import * as p from 'path';
import * as del from 'del';
import * as fs from 'fs-extra';
import Jasmine from 'jasmine';
import {config, Server} from 'karma';
import * as tmp from 'tmp';
import yargs from 'yargs/yargs';
import {SpecReporter} from 'jasmine-spec-reporter';
const args = yargs(process.argv.slice(2))
.parserConfiguration({'unknown-options-as-args': true})
.help(false)
.version(false)
.option('sassSassRepo', {
type: 'string',
description:
'The path to the sass/sass repo. Used to load type declarations.',
demand: true,
})
.option('sassPackage', {
type: 'string',
description: 'The path to the npm package that exports the Sass API.',
demand: true,
})
.option('browser', {
type: 'boolean',
description: 'Run the tests in a ChromeHeadless browser context.',
})
.option('help', {
type: 'boolean',
alias: 'h',
hidden: true,
});
const argv = args.parseSync();
if (argv.help) {
args.showHelp();
console.error('');
}
// Set up a temp directory that adds node_modules that depend on the given
// sassSassRepo and sassPackage.
const tmpObject = tmp.dirSync({
template: 'js-api-spec.XXXXXX',
unsafeCleanup: true,
});
const dir = tmpObject.name;
// TODO(nweiz): Use fs.rmSync() when we drop support for Node 12
del.sync(dir, {force: true});
const sassPackagePath = p.join(dir, 'node_modules', 'sass');
fs.mkdirSync(sassPackagePath, {recursive: true});
// We want to use the type information from --sassSassRepo even if --sassPackage
// is written in TypeScript, because the specs may test behavior that's not yet
// implemented in --sassPackage and we don't want that to cause a compile error.
// We accomplish this by creating a JavaScript package named "sass" that
// requires and re-exports --sassPackage, and using the type annotations from
// --sassSassRepo as that package's annotations.
const packageRequire = argv.browser
? p.resolve(argv.sassPackage, 'sass.default.js')
: p.resolve(argv.sassPackage);
fs.writeFileSync(
`${sassPackagePath}/index.js`,
`module.exports = require(${JSON.stringify(packageRequire)});`
);
// Load the APIs from the doc folder, since it uses plain .d.ts files instead of
// literate .d.ts.md files. The language repo's CI ensures the two remain in
// sync.
const specPath = p.join(argv.sassSassRepo, 'js-api-doc');
const specIndex = p.join(specPath, 'index.d.ts');
if (!fs.existsSync(specIndex)) {
console.error(`${specIndex} doesn't exist!`);
process.exit(1);
}
// Copy rather than symlinking so we don't end up using the Sass repo's
// `node_modules` directory.
fs.copySync(p.resolve(specPath), p.join(sassPackagePath, 'js-api'));
fs.writeFileSync(
p.join(sassPackagePath, 'package.json'),
JSON.stringify({
name: 'sass',
types: 'js-api/index.d.ts',
})
);
del.sync(p.join('js-api-spec', 'node_modules'));
fs.symlinkSync(
p.resolve(p.join(dir, 'node_modules')),
p.join('js-api-spec', 'node_modules')
);
process.on('exit', () => {
del.sync(p.join('js-api-spec', 'node_modules'));
tmpObject.removeCallback();
});
const specsToRun =
argv._.length > 0
? argv._.map(arg => arg.toString()).map(path =>
path.endsWith('.test.ts') ? path : '$path/**/*.test.ts'
)
: ['js-api-spec/**/*.test.ts'];
if (argv.browser) {
const karmaConfig = config.parseConfig(
p.resolve(__dirname, 'karma.config.js'),
{
port: 9876,
files: [
'js-api-spec/setup.ts',
...specsToRun.map(path =>
path.replace('*.test.ts', '!(*.node).test.ts')
),
],
},
{throwErrors: true}
);
const server = new Server(karmaConfig, exitCode => {
console.log('Karma has exited with ' + exitCode);
process.exit(exitCode);
});
server.start();
} else {
const jasmine = new Jasmine({
projectBaseDir: p.resolve('.'),
});
jasmine.env.clearReporters();
jasmine.env.addReporter(new SpecReporter());
jasmine.loadConfig({
spec_dir: 'js-api-spec',
spec_files: specsToRun.map(path => p.relative('js-api-spec', path)),
helpers: ['../node_modules/jasmine-expect/index.js', 'setup.ts'],
});
jasmine.execute();
}