Skip to content

Commit d2984e0

Browse files
committed
test(@angular-devkit/build-angular): add failing app-shell + sw test
1 parent a532bf8 commit d2984e0

File tree

2 files changed

+184
-75
lines changed

2 files changed

+184
-75
lines changed

packages/angular_devkit/build_angular/test/app-shell/app-shell_spec_large.ts

Lines changed: 177 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,117 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88
import { DefaultTimeout, runTargetSpec } from '@angular-devkit/architect/testing';
9-
import { normalize, virtualFs } from '@angular-devkit/core';
10-
import { tap } from 'rxjs/operators';
11-
import { host } from '../utils';
9+
import { getSystemPath, join, normalize, virtualFs } from '@angular-devkit/core';
10+
import * as express from 'express'; // tslint:disable-line:no-implicit-dependencies
11+
import { Server } from 'http';
12+
import { concatMap, tap } from 'rxjs/operators';
13+
import { host, protractorTargetSpec } from '../utils';
1214

1315

1416
describe('AppShell Builder', () => {
1517
beforeEach(done => host.initialize().toPromise().then(done, done.fail));
1618
afterEach(done => host.restore().toPromise().then(done, done.fail));
1719

1820
const targetSpec = { project: 'app', target: 'app-shell' };
21+
const appShellRouteFiles = {
22+
'src/app/app-shell/app-shell.component.html': `
23+
<p>
24+
app-shell works!
25+
</p>
26+
`,
27+
'src/app/app-shell/app-shell.component.ts': `
28+
import { Component, OnInit } from '@angular/core';
29+
30+
@Component({
31+
selector: 'app-app-shell',
32+
templateUrl: './app-shell.component.html',
33+
})
34+
export class AppShellComponent implements OnInit {
35+
36+
constructor() { }
37+
38+
ngOnInit() {
39+
}
40+
41+
}
42+
`,
43+
'src/app/app.module.ts': `
44+
import { BrowserModule } from '@angular/platform-browser';
45+
import { NgModule } from '@angular/core';
46+
47+
import { AppRoutingModule } from './app-routing.module';
48+
import { AppComponent } from './app.component';
49+
import { environment } from '../environments/environment';
50+
import { RouterModule } from '@angular/router';
51+
52+
@NgModule({
53+
declarations: [
54+
AppComponent
55+
],
56+
imports: [
57+
BrowserModule.withServerTransition({ appId: 'serverApp' }),
58+
AppRoutingModule,
59+
RouterModule
60+
],
61+
providers: [],
62+
bootstrap: [AppComponent]
63+
})
64+
export class AppModule { }
65+
`,
66+
'src/app/app.server.module.ts': `
67+
import { NgModule } from '@angular/core';
68+
import { ServerModule } from '@angular/platform-server';
69+
70+
import { AppModule } from './app.module';
71+
import { AppComponent } from './app.component';
72+
import { Routes, RouterModule } from '@angular/router';
73+
import { AppShellComponent } from './app-shell/app-shell.component';
74+
75+
const routes: Routes = [ { path: 'shell', component: AppShellComponent }];
76+
77+
@NgModule({
78+
imports: [
79+
AppModule,
80+
ServerModule,
81+
RouterModule.forRoot(routes),
82+
],
83+
bootstrap: [AppComponent],
84+
declarations: [AppShellComponent],
85+
})
86+
export class AppServerModule {}
87+
`,
88+
'src/main.ts': `
89+
import { enableProdMode } from '@angular/core';
90+
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
91+
92+
import { AppModule } from './app/app.module';
93+
import { environment } from './environments/environment';
94+
95+
if (environment.production) {
96+
enableProdMode();
97+
}
98+
99+
document.addEventListener('DOMContentLoaded', () => {
100+
platformBrowserDynamic().bootstrapModule(AppModule)
101+
.catch(err => console.log(err));
102+
});
103+
`,
104+
'src/app/app-routing.module.ts': `
105+
import { NgModule } from '@angular/core';
106+
import { Routes, RouterModule } from '@angular/router';
107+
108+
const routes: Routes = [];
109+
110+
@NgModule({
111+
imports: [RouterModule.forRoot(routes)],
112+
exports: [RouterModule]
113+
})
114+
export class AppRoutingModule { }
115+
`,
116+
'src/app/app.component.html': `
117+
<router-outlet></router-outlet>
118+
`,
119+
};
19120

20121
it('works (basic)', done => {
21122
host.replaceInFile('src/app/app.module.ts', / BrowserModule/, `
@@ -33,26 +134,46 @@ describe('AppShell Builder', () => {
33134
});
34135

35136
it('works with route', done => {
36-
host.writeMultipleFiles({
37-
'src/app/app-shell/app-shell.component.html': `
38-
<p>
39-
app-shell works!
40-
</p>
41-
`,
42-
'src/app/app-shell/app-shell.component.ts': `
43-
import { Component, OnInit } from '@angular/core';
44-
45-
@Component({
46-
selector: 'app-app-shell',
47-
templateUrl: './app-shell.component.html',
48-
})
49-
export class AppShellComponent implements OnInit {
50-
51-
constructor() { }
137+
host.writeMultipleFiles(appShellRouteFiles);
138+
const overrides = { route: 'shell' };
52139

53-
ngOnInit() {
54-
}
140+
runTargetSpec(host, targetSpec, overrides, DefaultTimeout * 2).pipe(
141+
tap((buildEvent) => expect(buildEvent.success).toBe(true)),
142+
tap(() => {
143+
const fileName = 'dist/index.html';
144+
const content = virtualFs.fileBufferToString(host.scopedSync().read(normalize(fileName)));
145+
expect(content).toContain('app-shell works!');
146+
}),
147+
).toPromise().then(done, done.fail);
148+
});
55149

150+
it('works with route and service-worker', done => {
151+
host.writeMultipleFiles(appShellRouteFiles);
152+
host.writeMultipleFiles({
153+
'src/ngsw-config.json': `
154+
{
155+
"index": "/index.html",
156+
"assetGroups": [{
157+
"name": "app",
158+
"installMode": "prefetch",
159+
"resources": {
160+
"files": [
161+
"/favicon.ico",
162+
"/index.html",
163+
"/*.css",
164+
"/*.js"
165+
]
166+
}
167+
}, {
168+
"name": "assets",
169+
"installMode": "lazy",
170+
"updateMode": "prefetch",
171+
"resources": {
172+
"files": [
173+
"/assets/**"
174+
]
175+
}
176+
}]
56177
}
57178
`,
58179
'src/app/app.module.ts': `
@@ -61,6 +182,7 @@ describe('AppShell Builder', () => {
61182
62183
import { AppRoutingModule } from './app-routing.module';
63184
import { AppComponent } from './app.component';
185+
import { ServiceWorkerModule } from '@angular/service-worker';
64186
import { environment } from '../environments/environment';
65187
import { RouterModule } from '@angular/router';
66188
@@ -71,77 +193,59 @@ describe('AppShell Builder', () => {
71193
imports: [
72194
BrowserModule.withServerTransition({ appId: 'serverApp' }),
73195
AppRoutingModule,
196+
ServiceWorkerModule.register('/ngsw-worker.js', { enabled: environment.production }),
74197
RouterModule
75198
],
76199
providers: [],
77200
bootstrap: [AppComponent]
78201
})
79202
export class AppModule { }
80203
`,
81-
'src/app/app.server.module.ts': `
82-
import { NgModule } from '@angular/core';
83-
import { ServerModule } from '@angular/platform-server';
84-
85-
import { AppModule } from './app.module';
86-
import { AppComponent } from './app.component';
87-
import { Routes, RouterModule } from '@angular/router';
88-
import { AppShellComponent } from './app-shell/app-shell.component';
89-
90-
const routes: Routes = [ { path: 'shell', component: AppShellComponent }];
91-
92-
@NgModule({
93-
imports: [
94-
AppModule,
95-
ServerModule,
96-
RouterModule.forRoot(routes),
97-
],
98-
bootstrap: [AppComponent],
99-
declarations: [AppShellComponent],
100-
})
101-
export class AppServerModule {}
102-
`,
103-
'src/main.ts': `
104-
import { enableProdMode } from '@angular/core';
105-
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
106-
107-
import { AppModule } from './app/app.module';
108-
import { environment } from './environments/environment';
109-
110-
if (environment.production) {
111-
enableProdMode();
112-
}
113-
114-
document.addEventListener('DOMContentLoaded', () => {
115-
platformBrowserDynamic().bootstrapModule(AppModule)
116-
.catch(err => console.log(err));
204+
'e2e/app.e2e-spec.ts': `
205+
import { browser, by, element } from 'protractor';
206+
207+
it('should have ngsw in normal state', () => {
208+
browser.get('/');
209+
// Wait for service worker to load.
210+
browser.sleep(2000);
211+
browser.waitForAngularEnabled(false);
212+
browser.get('/ngsw/state');
213+
// Should have updated, and be in normal state.
214+
expect(element(by.css('pre')).getText()).not.toContain('Last update check: never');
215+
expect(element(by.css('pre')).getText()).toContain('Driver state: NORMAL');
117216
});
118217
`,
119-
'src/app/app-routing.module.ts': `
120-
import { NgModule } from '@angular/core';
121-
import { Routes, RouterModule } from '@angular/router';
122-
123-
const routes: Routes = [];
124-
125-
@NgModule({
126-
imports: [RouterModule.forRoot(routes)],
127-
exports: [RouterModule]
128-
})
129-
export class AppRoutingModule { }
130-
`,
131-
'src/app/app.component.html': `
132-
<router-outlet></router-outlet>
133-
`,
134218
});
219+
// This should match the browser target prod config.
220+
host.replaceInFile(
221+
'angular.json',
222+
'"buildOptimizer": true',
223+
'"buildOptimizer": true, "serviceWorker": true',
224+
);
135225

136226
const overrides = { route: 'shell' };
227+
const prodTargetSpec = { ...targetSpec, configuration: 'production' };
228+
let server: Server;
137229

138-
runTargetSpec(host, targetSpec, overrides, DefaultTimeout * 2).pipe(
230+
// Build the app shell.
231+
runTargetSpec(host, prodTargetSpec, overrides, DefaultTimeout * 2).pipe(
139232
tap((buildEvent) => expect(buildEvent.success).toBe(true)),
233+
// Make sure the index is pre-rendering the route.
140234
tap(() => {
141235
const fileName = 'dist/index.html';
142236
const content = virtualFs.fileBufferToString(host.scopedSync().read(normalize(fileName)));
143237
expect(content).toContain('app-shell works!');
144238
}),
239+
tap(() => {
240+
// Serve the app using a simple static server.
241+
const app = express();
242+
app.use('/', express.static(getSystemPath(join(host.root(), 'dist')) + '/'));
243+
server = app.listen(4200);
244+
}),
245+
// Load app in protractor, then check service worker status.
246+
concatMap(() => runTargetSpec(host, protractorTargetSpec, { devServerTarget: undefined })),
247+
// Close the express server.
248+
tap(() => server.close()),
145249
).toPromise().then(done, done.fail);
146250
});
147251
});

tests/angular_devkit/build_angular/hello-world-app/angular.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@
3535
"production": {
3636
"fileReplacements": [
3737
{
38-
"replace": "src/environments/environments.ts",
39-
"with": "src/environments/environments.prod.ts"
38+
"replace": "src/environments/environment.ts",
39+
"with": "src/environments/environment.prod.ts"
4040
}
4141
],
4242
"optimization": true,
@@ -65,6 +65,11 @@
6565
"options": {
6666
"browserTarget": "app:build",
6767
"serverTarget": "app:server"
68+
},
69+
"configurations": {
70+
"production": {
71+
"browserTarget": "app:build:production"
72+
}
6873
}
6974
},
7075
"serve": {

0 commit comments

Comments
 (0)