UNPKG

15.1 kBJavaScriptView Raw
1"use strict";
2/**
3 * @license
4 * Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
5 * This code may only be used under the BSD style license found at
6 * http://polymer.github.io/LICENSE.txt
7 * The complete set of authors may be found at
8 * http://polymer.github.io/AUTHORS.txt
9 * The complete set of contributors may be found at
10 * http://polymer.github.io/CONTRIBUTORS.txt
11 * Code distributed by Google as part of the polymer project is also
12 * subject to an additional IP rights grant found at
13 * http://polymer.github.io/PATENTS.txt
14 */
15var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
16 return new (P || (P = Promise))(function (resolve, reject) {
17 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
18 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
19 function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
20 step((generator = generator.apply(thisArg, _arguments || [])).next());
21 });
22};
23Object.defineProperty(exports, "__esModule", { value: true });
24const chai_1 = require("chai");
25const path = require("path");
26const polymer_project_config_1 = require("polymer-project-config");
27const sinon = require("sinon");
28const stream_1 = require("stream");
29const util_1 = require("./util");
30const analyzer_1 = require("../analyzer");
31const streams_1 = require("../streams");
32/**
33 * Streams will remain paused unless something is listening for it's data.
34 * NoopStream is useful for piping to if you just want the stream to run and end
35 * successfully without checking the data passed through it.
36 */
37class NoopStream extends stream_1.Writable {
38 constructor() {
39 super({ objectMode: true });
40 }
41 _write(_chunk, _encoding, callback) {
42 callback();
43 }
44}
45suite('Analyzer', () => {
46 suite('DepsIndex', () => {
47 test('fragment to deps list has only uniques', () => {
48 const config = new polymer_project_config_1.ProjectConfig({
49 root: `test-fixtures/analyzer-data`,
50 entrypoint: 'entrypoint.html',
51 fragments: [
52 'a.html',
53 'b.html',
54 ],
55 sources: ['a.html', 'b.html', 'entrypoint.html'],
56 });
57 const analyzer = new analyzer_1.BuildAnalyzer(config, null);
58 analyzer.sources().pipe(new NoopStream());
59 analyzer.dependencies().pipe(new NoopStream());
60 return streams_1.waitForAll([analyzer.sources(), analyzer.dependencies()])
61 .then(() => {
62 return analyzer.analyzeDependencies;
63 })
64 .then((depsIndex) => {
65 const ftd = depsIndex.fragmentToDeps;
66 for (const frag of ftd.keys()) {
67 chai_1.assert.deepEqual(ftd.get(frag), ['shared-1.html', 'shared-2.html'].map((u) => u));
68 }
69 });
70 });
71 test('analyzing shell and entrypoint doesn\'t double load files', () => {
72 const root = `test-fixtures/analyzer-data`;
73 const sourceFiles = ['shell.html', 'entrypoint.html'].map((p) => path.resolve(root, p));
74 const config = new polymer_project_config_1.ProjectConfig({
75 root: root,
76 entrypoint: 'entrypoint.html',
77 shell: 'shell.html',
78 sources: sourceFiles,
79 });
80 const analyzer = new analyzer_1.BuildAnalyzer(config, null);
81 analyzer.sources().pipe(new NoopStream());
82 analyzer.dependencies().pipe(new NoopStream());
83 return streams_1.waitForAll([analyzer.sources(), analyzer.dependencies()])
84 .then(() => {
85 return analyzer.analyzeDependencies;
86 })
87 .then((depsIndex) => {
88 chai_1.assert.isTrue(depsIndex.depsToFragments.has('shared-2.html'));
89 chai_1.assert.isFalse(depsIndex.depsToFragments.has('shell.html'));
90 chai_1.assert.isFalse(depsIndex.depsToFragments.has('shared-banana.html'));
91 });
92 });
93 });
94 suite('.dependencies', () => {
95 test('outputs all dependencies needed by source', () => {
96 const foundDependencies = new Set();
97 const root = `test-fixtures/analyzer-data`;
98 const sourceFiles = ['shell.html', 'entrypoint.html'].map((p) => path.resolve(root, p));
99 const config = new polymer_project_config_1.ProjectConfig({
100 root: root,
101 entrypoint: 'entrypoint.html',
102 shell: 'shell.html',
103 sources: sourceFiles,
104 });
105 const analyzer = new analyzer_1.BuildAnalyzer(config, null);
106 analyzer.sources().pipe(new NoopStream());
107 analyzer.dependencies().on('data', (file) => {
108 foundDependencies.add(file.path);
109 });
110 return streams_1.waitForAll([analyzer.sources(), analyzer.dependencies()])
111 .then(() => {
112 // shared-1 is never imported by shell/entrypoint, so it is not
113 // included as a dep.
114 chai_1.assert.isFalse(foundDependencies.has(path.resolve(root, 'shared-1.html')));
115 // shared-2 is imported by shell, so it is included as a dep.
116 chai_1.assert.isTrue(foundDependencies.has(path.resolve(root, 'shared-2.html')));
117 });
118 });
119 test('outputs all dependencies needed by source and given fragments', () => {
120 const foundDependencies = new Set();
121 const root = `test-fixtures/analyzer-data`;
122 const sourceFiles = ['a.html', 'b.html', 'shell.html', 'entrypoint.html'].map((p) => path.resolve(root, p));
123 const config = new polymer_project_config_1.ProjectConfig({
124 root: root,
125 entrypoint: 'entrypoint.html',
126 shell: 'shell.html',
127 fragments: [
128 'a.html',
129 'b.html',
130 ],
131 sources: sourceFiles,
132 });
133 const analyzer = new analyzer_1.BuildAnalyzer(config, null);
134 analyzer.sources().pipe(new NoopStream());
135 analyzer.dependencies().on('data', (file) => {
136 foundDependencies.add(file.path);
137 });
138 return streams_1.waitForAll([analyzer.sources(), analyzer.dependencies()])
139 .then(() => {
140 // shared-1 is imported by 'a' & 'b', so it is included as a
141 // dep.
142 chai_1.assert.isTrue(foundDependencies.has(path.resolve(root, 'shared-1.html')));
143 // shared-1 is imported by 'a' & 'b', so it is included as a
144 // dep.
145 chai_1.assert.isTrue(foundDependencies.has(path.resolve(root, 'shared-2.html')));
146 });
147 });
148 });
149 test('propagates an error when a dependency filepath is analyzed but cannot be found', (done) => {
150 const root = `test-fixtures/bad-src-import`;
151 const config = new polymer_project_config_1.ProjectConfig({
152 root: root,
153 entrypoint: 'index.html',
154 sources: ['src/**/*'],
155 });
156 const analyzer = new analyzer_1.BuildAnalyzer(config, null);
157 let errorCounter = 0;
158 const errorListener = (err) => {
159 chai_1.assert.equal(err.message, '3 error(s) occurred during build.');
160 errorCounter++;
161 if (errorCounter >= 2) {
162 done();
163 }
164 };
165 analyzer.sources().pipe(new NoopStream());
166 analyzer.sources().on('error', errorListener);
167 analyzer.dependencies().pipe(new NoopStream());
168 analyzer.dependencies().on('error', errorListener);
169 });
170 test('propagates an error when a source filepath is analyzed but cannot be found', (done) => {
171 const root = `test-fixtures/bad-dependency-import`;
172 const config = new polymer_project_config_1.ProjectConfig({
173 root: root,
174 entrypoint: 'index.html',
175 sources: ['src/**/*'],
176 });
177 const analyzer = new analyzer_1.BuildAnalyzer(config, null);
178 analyzer.dependencies().pipe(new NoopStream());
179 analyzer.dependencies().on('error', (err) => {
180 chai_1.assert.match(err.message, /ENOENT\: no such file or directory.*does\-not\-exist\-in\-dependencies\.html/);
181 done();
182 });
183 });
184 test('both file streams will emit a analysis warning of type "error"', (done) => {
185 const root = path.resolve('test-fixtures/project-analysis-error');
186 const sourceFiles = path.join(root, '**');
187 const config = new polymer_project_config_1.ProjectConfig({
188 root: root,
189 sources: [sourceFiles],
190 });
191 const analyzer = new analyzer_1.BuildAnalyzer(config, null);
192 let errorCounter = 0;
193 const errorListener = (err) => {
194 chai_1.assert.equal(err.message, '1 error(s) occurred during build.');
195 errorCounter++;
196 if (errorCounter >= 2) {
197 done();
198 }
199 };
200 analyzer.sources().pipe(new NoopStream());
201 analyzer.sources().on('error', errorListener);
202 analyzer.dependencies().pipe(new NoopStream());
203 analyzer.dependencies().on('error', errorListener);
204 });
205 test('the analyzer stream will log all analysis warnings at the end of the stream', () => {
206 const root = path.resolve('test-fixtures/project-analysis-error');
207 const sourceFiles = path.join(root, '**');
208 const config = new polymer_project_config_1.ProjectConfig({
209 root: root,
210 sources: [sourceFiles],
211 });
212 let prematurePrintWarnings = false;
213 const prematurePrintWarningsCheck = () => prematurePrintWarnings =
214 prematurePrintWarnings ||
215 analyzer.allFragmentsToAnalyze.size > 0 && printWarningsSpy.called;
216 const analyzer = new analyzer_1.BuildAnalyzer(config, null);
217 const printWarningsSpy = sinon.spy(analyzer, 'printWarnings');
218 analyzer.sources().on('data', prematurePrintWarningsCheck);
219 analyzer.dependencies().on('data', prematurePrintWarningsCheck);
220 return streams_1.waitForAll([analyzer.sources(), analyzer.dependencies()])
221 .then(() => {
222 throw new Error('Parse error expected!');
223 }, (_err) => {
224 chai_1.assert.isFalse(prematurePrintWarnings);
225 chai_1.assert.isTrue(printWarningsSpy.calledOnce);
226 });
227 });
228 test('analyzer filters warnings', () => {
229 const root = path.resolve('test-fixtures/project-analysis-warning');
230 const sources = [path.join(root, '**')];
231 const config = new polymer_project_config_1.ProjectConfig({
232 root,
233 sources,
234 lint: { rules: ['polymer-2'], ignoreWarnings: ['invalid-polymer-expression'] }
235 });
236 const analyzer = new analyzer_1.BuildAnalyzer(config, null);
237 analyzer.sources().pipe(new NoopStream());
238 return streams_1.waitFor(analyzer.sources()).then(() => {
239 chai_1.assert.isTrue(analyzer.warnings.size === 0);
240 });
241 });
242 test('calling sources() starts analysis', () => __awaiter(this, void 0, void 0, function* () {
243 const config = new polymer_project_config_1.ProjectConfig({
244 root: `test-fixtures/analyzer-data`,
245 entrypoint: 'entrypoint.html',
246 fragments: [
247 'a.html',
248 'b.html',
249 ],
250 sources: ['a.html', 'b.html', 'entrypoint.html'],
251 });
252 const analyzer = new analyzer_1.BuildAnalyzer(config, null);
253 chai_1.assert.isFalse(analyzer.started);
254 analyzer.sources().pipe(new NoopStream());
255 chai_1.assert.isTrue(analyzer.started);
256 }));
257 test('calling dependencies() starts analysis', () => {
258 const config = new polymer_project_config_1.ProjectConfig({
259 root: `test-fixtures/analyzer-data`,
260 entrypoint: 'entrypoint.html',
261 fragments: [
262 'a.html',
263 'b.html',
264 ],
265 sources: ['a.html', 'b.html', 'entrypoint.html'],
266 });
267 const analyzer = new analyzer_1.BuildAnalyzer(config, null);
268 chai_1.assert.isFalse(analyzer.started);
269 analyzer.dependencies().pipe(new NoopStream());
270 chai_1.assert.isTrue(analyzer.started);
271 });
272 test('the source/dependency streams remain paused until use', () => {
273 const config = new polymer_project_config_1.ProjectConfig({
274 root: `test-fixtures/analyzer-data`,
275 entrypoint: 'entrypoint.html',
276 fragments: [
277 'a.html',
278 'b.html',
279 ],
280 sources: ['a.html', 'b.html', 'entrypoint.html'],
281 });
282 const analyzer = new analyzer_1.BuildAnalyzer(config, null);
283 // Cast analyzer to <any> so that we can check private properties of it.
284 // We need to access these private streams directly because the public
285 // `sources()` and `dependencies()` functions have intentional side effects
286 // related to these streams that we are trying to test here.
287 // tslint:disable-next-line: no-any
288 const analyzerWithPrivates = analyzer;
289 chai_1.assert.isUndefined(analyzerWithPrivates._sourcesStream);
290 chai_1.assert.isUndefined(analyzerWithPrivates._dependenciesStream);
291 analyzerWithPrivates.sources();
292 chai_1.assert.isDefined(analyzerWithPrivates._sourcesStream);
293 chai_1.assert.isDefined(analyzerWithPrivates._dependenciesStream);
294 chai_1.assert.isTrue(util_1.getFlowingState(analyzerWithPrivates._sourcesStream));
295 chai_1.assert.isTrue(util_1.getFlowingState(analyzerWithPrivates._dependenciesStream));
296 // Check that even though `sources()` has been called, the public file
297 // streams aren't flowing until data listeners are attached (directly or via
298 // piping) so that files are never lost).
299 chai_1.assert.isNull(util_1.getFlowingState(analyzer.sources()));
300 chai_1.assert.isNull(util_1.getFlowingState(analyzer.dependencies()));
301 analyzer.sources().on('data', () => { });
302 chai_1.assert.isTrue(util_1.getFlowingState(analyzer.sources()));
303 chai_1.assert.isNull(util_1.getFlowingState(analyzer.dependencies()));
304 analyzer.dependencies().pipe(new NoopStream());
305 chai_1.assert.isTrue(util_1.getFlowingState(analyzer.sources()));
306 chai_1.assert.isTrue(util_1.getFlowingState(analyzer.dependencies()));
307 });
308 // TODO(fks) 10-26-2016: Refactor logging to be testable, and configurable by
309 // the consumer.
310 suite.skip('.printWarnings()', () => { });
311});
312//# sourceMappingURL=analyzer_test.js.map
\No newline at end of file