diff --git a/tools/gulp/tasks/lint.ts b/tools/gulp/tasks/lint.ts index e2a705d5eb6..2d3da977b75 100644 --- a/tools/gulp/tasks/lint.ts +++ b/tools/gulp/tasks/lint.ts @@ -2,7 +2,7 @@ import gulp = require('gulp'); import {execNodeTask} from '../util/task_helpers'; import {DIST_MATERIAL} from '../constants'; -gulp.task('lint', ['tslint', 'stylelint', 'madge']); +gulp.task('lint', ['tslint', 'stylelint', 'madge', 'dashboardlint']); /** Task that runs madge to detect circular dependencies. */ gulp.task('madge', ['library:clean-build'], execNodeTask('madge', ['--circular', DIST_MATERIAL])); @@ -12,5 +12,11 @@ gulp.task('stylelint', execNodeTask( 'stylelint', ['src/**/*.scss', '--config', 'stylelint-config.json', '--syntax', 'scss'] )); +gulp.task('dashboardlint', execNodeTask( + 'stylelint', ['tools/screenshot-test/**/*.css', '--config', 'stylelint-config.json', + '--syntax', 'scss'] +)); + /** Task to run TSLint against the e2e/ and src/ directories. */ -gulp.task('tslint', execNodeTask('tslint', ['-c', 'tslint.json', '+(src|e2e|tools)/**/*.ts'])); +gulp.task('tslint', execNodeTask('tslint', ['-c', 'tslint.json', '+(src|e2e|tools)/**/*.ts', + '--exclude', '**/node_modules/**/*'])); diff --git a/tools/screenshot-test/angular-cli.json b/tools/screenshot-test/angular-cli.json new file mode 100644 index 00000000000..d5333d77e2e --- /dev/null +++ b/tools/screenshot-test/angular-cli.json @@ -0,0 +1,47 @@ +{ + "project": { + "version": "1.0.0-beta.26", + "name": "screenshot-test" + }, + "apps": [ + { + "root": "src", + "outDir": "dist", + "assets": [ + "assets", + "favicon.ico" + ], + "index": "index.html", + "main": "main.ts", + "test": "test.ts", + "tsconfig": "tsconfig.json", + "prefix": "app", + "mobile": false, + "styles": [ + "styles.css" + ], + "scripts": [], + "environmentSource": "environments/environment.ts", + "environment": { + "dev": "environments/environment.ts", + "prod": "environments/environment.prod.ts" + } + } + ], + "defaults": { + "styleExt": "css", + "prefixInterfaces": false, + "inline": { + "style": false, + "template": false + }, + "spec": { + "class": false, + "component": true, + "directive": true, + "module": false, + "pipe": true, + "service": true + } + } +} diff --git a/tools/screenshot-test/package.json b/tools/screenshot-test/package.json new file mode 100644 index 00000000000..25242b3ad90 --- /dev/null +++ b/tools/screenshot-test/package.json @@ -0,0 +1,36 @@ +{ + "name": "screenshot-test", + "version": "0.0.0", + "license": "MIT", + "angular-cli": {}, + "scripts": { + "ng": "ng", + "start": "ng serve" + }, + "private": true, + "dependencies": { + "@angular/animations": "^4.0.2", + "@angular/common": "^4.0.0", + "@angular/compiler": "^4.0.0", + "@angular/compiler-cli": "^4.0.0", + "@angular/core": "^4.0.0", + "@angular/forms": "^4.0.0", + "@angular/http": "^4.0.0", + "@angular/material": "^2.0.0-beta.3", + "@angular/platform-browser": "^4.0.0", + "@angular/platform-browser-dynamic": "^4.0.0", + "@angular/router": "^4.0.0", + "core-js": "^2.4.1", + "firebase": "^3.7.6", + "rxjs": "^5.0.1", + "ts-helpers": "^1.1.1", + "zone.js": "^0.8.4" + }, + "devDependencies": { + "@angular/cli": "^1.0.0", + "@angular/compiler-cli": "^4.0.0", + "@types/node": "^6.0.42", + "ts-node": "1.2.1", + "typescript": "~2.2.1" + } +} diff --git a/tools/screenshot-test/src/app/firebase.service.ts b/tools/screenshot-test/src/app/firebase.service.ts new file mode 100644 index 00000000000..aa05e358a24 --- /dev/null +++ b/tools/screenshot-test/src/app/firebase.service.ts @@ -0,0 +1,176 @@ +import {Injectable} from '@angular/core'; +import {Http} from '@angular/http'; +import * as firebase from 'firebase'; +import 'rxjs/add/operator/toPromise'; + +const config = require('../config.json'); + +import {ScreenshotResultSummary} from './screenshot-result'; + +/** The service to fetch data from firebase database */ +@Injectable() +export class FirebaseService { + + /** The current user */ + user: firebase.User; + + /** The screenshot results */ + screenshotResultSummary: ScreenshotResultSummary; + + constructor(private _http: Http) { + // Initialize Firebase + firebase.initializeApp(config.firebase); + + firebase.auth().onAuthStateChanged((user: firebase.User) => { + this.user = user; + }); + } + + + /** Get the firebase storage test image folder url */ + getTestScreenshotImageUrl(filename: string): firebase.Promise { + return this._storageRef().child('test').child(filename).getDownloadURL(); + } + + /** Get the firebase storage diff image folder url */ + getDiffScreenshotImageUrl(filename: string): firebase.Promise { + return this._storageRef().child('diff').child(filename).getDownloadURL(); + } + + /** Get the firebase storage golden image folder url */ + getGoldScreenshotImageUrl(filename: string): firebase.Promise { + return firebase.storage().ref('goldens').child(filename).getDownloadURL(); + } + + /** Set pull request number. All test information and pull request information will be retrived + * from database + */ + set prNumber(prNumber: string){ + this.screenshotResultSummary = new ScreenshotResultSummary(); + this.screenshotResultSummary.prNumber = prNumber; + this._readPullRequestScreenshotReport(); + } + + _readPullRequestScreenshotReport() { + if (!this.screenshotResultSummary.prNumber) { + return; + } + + this._databaseRef().on('value', (snapshot: firebase.database.DataSnapshot) => { + let counter = 0; + snapshot.forEach((childSnapshot: firebase.database.DataSnapshot) => { + let childValue = childSnapshot.val(); + switch (childSnapshot.key) { + case 'sha': + this._readSha(childValue); + break; + case 'travis': + this.screenshotResultSummary.travis = childValue; + break; + case 'results': + this._readResults(childSnapshot); + break; + } + counter++; + if (counter === snapshot.numChildren()) { + return true; + } + }); + }); + } + + signIntoGithub(): firebase.Promise { + return firebase.auth().signInWithRedirect(new firebase.auth.GithubAuthProvider()); + } + + signOutFromGithub() { + firebase.auth().signOut(); + } + + /** Change the PR status to approved to let Firebase Functions copy test images to goldens */ + approvePullRequest() { + return this._databaseRef().child('approved').child(this.screenshotResultSummary.sha) + .set(Date.now()); + } + + /** + * Change the commit's screenshot test status on GitHub + * The value in result/$sha/$result will trigger GitHub status update: + * true - The GitHub status for this SHA will become `success` for Screenshot Test + * false - The GitHub status for this SHA will become `failure` for Screenshot Test + * In this dashboard, we only approve pull requests, so the value is always `true` + */ + updatePullRequestResult() { + return this._databaseRef().child('result').child(this.screenshotResultSummary.sha) + .set(true); + } + + /** Reference to the firebase database where the JSON test results and meatadate is stored. */ + _databaseRef(): firebase.database.Reference { + return firebase.database().ref('screenshot').child('reports') + .child(this.screenshotResultSummary.prNumber); + } + + /** Reference to the firebase storage bucket where the screenshot PNG files are stored. */ + _storageRef(): firebase.storage.Reference { + return firebase.storage().ref('screenshots').child(this.screenshotResultSummary.prNumber); + } + + /** Read the results from database adn put the results in screenshotReusltSummary */ + _readResults(childSnapshot: firebase.database.DataSnapshot) { + let childCounter = 0; + this.screenshotResultSummary.collapse = []; + this.screenshotResultSummary.testNames = []; + this.screenshotResultSummary.testResultsByName.clear(); + childSnapshot.forEach((resultSnapshot: firebase.database.DataSnapshot) => { + this._addTestResults(resultSnapshot.key, resultSnapshot.val()); + childCounter++; + if (childCounter === childSnapshot.numChildren()) { + return true; + } + }); + } + + _addTestResults(name: string, value: boolean) { + this.screenshotResultSummary.testResultsByName.set(name, value); + this.screenshotResultSummary.testNames.push(name); + this.screenshotResultSummary.collapse.push(value); + } + + /** Read SHA and approved status from database and put them in ScreenshotResultSummary */ + _readSha(childValue) { + this.screenshotResultSummary.sha = childValue; + // Get github status + this.getGithubStatus(); + // Get test allTestsPassedOrApproved + this._databaseRef().child(`result/${childValue}`).once('value') + .then((dataSnapshot: firebase.database.DataSnapshot) => { + this.screenshotResultSummary.allTestsPassedOrApproved = dataSnapshot.val(); + }); + // Get the approved SHA and date time + this._databaseRef().child(`approved/${childValue}`).once('value') + .then((dataSnapshot: firebase.database.DataSnapshot) => { + this.screenshotResultSummary.approvedTime = dataSnapshot.val(); + }); + } + + getGithubStatus() { + let url = + `https://api.github.com/repos/${config.repoSlug}/commits/` + + `${this.screenshotResultSummary.sha}/status`; + return this._http.get(url).toPromise() + .then((response) => { + let statusResponse = response.json(); + let screenshotStatus = statusResponse.statuses.find((status) => + status.context === 'Screenshot Tests'); + switch (screenshotStatus && screenshotStatus.state) { + case 'success': + this.screenshotResultSummary.githubStatus = true; + break; + case 'failure': + this.screenshotResultSummary.githubStatus = false; + return; + } + }); + } +} diff --git a/tools/screenshot-test/src/app/nav/nav.component.html b/tools/screenshot-test/src/app/nav/nav.component.html new file mode 100644 index 00000000000..e7904d4f56e --- /dev/null +++ b/tools/screenshot-test/src/app/nav/nav.component.html @@ -0,0 +1,6 @@ + +
{{user.email}}
+ + +
+ diff --git a/tools/screenshot-test/src/app/nav/nav.component.ts b/tools/screenshot-test/src/app/nav/nav.component.ts new file mode 100644 index 00000000000..4fe73880097 --- /dev/null +++ b/tools/screenshot-test/src/app/nav/nav.component.ts @@ -0,0 +1,24 @@ +import {Component} from '@angular/core'; +import {FirebaseService} from '../firebase.service'; + + +/** Nav bar with ability to sign in or sign out Github account */ +@Component({ + selector: 'app-nav', + templateUrl: './nav.component.html' +}) +export class NavComponent { + get user() { + return this._service.user; + } + + constructor(private _service: FirebaseService) { } + + signIntoGithub() { + this._service.signIntoGithub(); + } + + signOutFromGithub() { + this._service.signOutFromGithub(); + } +} diff --git a/tools/screenshot-test/src/app/pixacto.dashboard.component.ts b/tools/screenshot-test/src/app/pixacto.dashboard.component.ts new file mode 100644 index 00000000000..19986bba7ac --- /dev/null +++ b/tools/screenshot-test/src/app/pixacto.dashboard.component.ts @@ -0,0 +1,10 @@ +import {Component} from '@angular/core'; + +@Component({ + selector: 'app-root', + template: ` + + + ` +}) +export class PixactoDashboardComponent {} diff --git a/tools/screenshot-test/src/app/pixacto.dashboard.module.ts b/tools/screenshot-test/src/app/pixacto.dashboard.module.ts new file mode 100644 index 00000000000..6ad767b70e1 --- /dev/null +++ b/tools/screenshot-test/src/app/pixacto.dashboard.module.ts @@ -0,0 +1,33 @@ +import {BrowserModule} from '@angular/platform-browser'; +import {NgModule} from '@angular/core'; +import {FormsModule} from '@angular/forms'; +import {HttpModule} from '@angular/http'; +import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; +import {MaterialModule} from '@angular/material'; +import {FirebaseService} from './firebase.service'; +import {routing} from './routes'; + +import {PixactoDashboardComponent} from './pixacto.dashboard.component'; +import {ViewerComponent} from './viewer/viewer.component'; +import {ResultComponent} from './result/result.component'; +import {NavComponent} from './nav/nav.component'; + +@NgModule({ + declarations: [ + PixactoDashboardComponent, + ViewerComponent, + ResultComponent, + NavComponent + ], + imports: [ + BrowserModule, + BrowserAnimationsModule, + FormsModule, + HttpModule, + MaterialModule, + routing, + ], + providers: [FirebaseService], + bootstrap: [PixactoDashboardComponent] +}) +export class PixactoDashboardModule { } diff --git a/tools/screenshot-test/src/app/result/result.component.css b/tools/screenshot-test/src/app/result/result.component.css new file mode 100644 index 00000000000..2509c8dd0a8 --- /dev/null +++ b/tools/screenshot-test/src/app/result/result.component.css @@ -0,0 +1,58 @@ +img { + border: 1px solid #666; + width: 100%; +} + +.images-section { + display:flex; +} + +.image-title { + text-transform: uppercase; +} + +.image-section { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.side-by-side .diff-section { + display: none; +} + +.flip .diff-section { + visibility: hidden; +} + +.flip .test-section, +.flip .gold-section { + position: absolute; + top: 80px; + left: 0; +} + +.flip .test-section { + visibility: visible; +} + +.flip .gold-section { + visibility: hidden; +} + +.flip.flipping .test-section { + visibility: hidden; +} + +.flip.flipping .gold-section { + visibility: visible; +} + +.failed { + color: red; +} + +.passed { + color: forestgreen; +} diff --git a/tools/screenshot-test/src/app/result/result.component.html b/tools/screenshot-test/src/app/result/result.component.html new file mode 100644 index 00000000000..cfe3312f2f7 --- /dev/null +++ b/tools/screenshot-test/src/app/result/result.component.html @@ -0,0 +1,39 @@ + + + + {{collapseIcon}} + {{testName}} + + {{resultText}} + + +
+
+
Test image
+
+
+
+
Diff image
+
+
+
+
Reference image
+
+
+
+
+ + + + Diff + + + Flip + + + Side by side + + + + +
diff --git a/tools/screenshot-test/src/app/result/result.component.ts b/tools/screenshot-test/src/app/result/result.component.ts new file mode 100644 index 00000000000..1c9b05cb950 --- /dev/null +++ b/tools/screenshot-test/src/app/result/result.component.ts @@ -0,0 +1,126 @@ +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + Input, + Output, + EventEmitter +} from '@angular/core'; +import {FirebaseService} from '../firebase.service'; + +/** + * Component to display test result, test name, test image, reference image, and diff image. + * User can change the view mode, or collapse the panel to hide the images. + */ +@Component({ + selector: 'app-result', + templateUrl: './result.component.html', + styleUrls: ['./result.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ResultComponent { + + /** Test name, display on top of the result card */ + testName: string; + + /** Test, diff and golden image urls */ + testImageUrl: string; + diffImageUrl: string; + goldImageUrl: string; + + /** + * Test result, auto set collapse to be the same as the result value + */ + @Input() + get result() { + return this._result; + } + set result(value: boolean) { + this._result = value; + this.collapse = value; + } + _result: boolean; + + get resultText() { + return this._result ? 'Passed' : 'Failed'; + } + + /** Collapse: whether collapse or expand the card to show images */ + @Input() collapse: boolean = true; + + /** Mode: the result card has three modes, flip, side by side, and diff */ + @Input() + get mode() { + return this._mode; + } + set mode(value: 'flip' | 'side-by-side' | 'diff') { + this._mode = value; + this.modeEvent.emit(value); + this._changeDetectorRef.markForCheck(); + } + _mode: 'flip' | 'side-by-side' | 'diff' = 'diff'; + + /** When mode is "flip" whether we show the test image or the golden image */ + @Input() + get flipping() { + return this._flipping; + } + + set flipping(value: boolean) { + this._flipping = value; + this.flippingEvent.emit(value); + this._changeDetectorRef.markForCheck(); + } + _flipping: boolean = false; + + get collapseIcon() { + return this.collapse ? 'keyboard_arrow_right' : 'keyboard_arrow_down'; + } + + @Input() + set filename(filename: string) { + if (this._filename != filename) { + this._filename = filename; + this.setFilenameAndFetchImages(); + } + } + _filename: string; + + setFilenameAndFetchImages() { + this.testName = this._filename.replace(/[_]/g, ' '); + let imageFilename = `${this._filename}.screenshot.png`; + this.service.getTestScreenshotImageUrl(imageFilename) + .then((url) => { + this.testImageUrl = url; + this._changeDetectorRef.markForCheck(); + }); + this.service.getDiffScreenshotImageUrl(imageFilename) + .then((url) => { + this.diffImageUrl = url; + this._changeDetectorRef.markForCheck(); + }); + this.service.getGoldScreenshotImageUrl(imageFilename) + .then((url) => { + this.goldImageUrl = url; + this._changeDetectorRef.markForCheck(); + }); + } + + @Output('flippingChange') flippingEvent = new EventEmitter(); + + @Output('modeChange') modeEvent = new EventEmitter<'flip' | 'side-by-side' | 'diff'>(); + + @Output('collapseChange') collapseEvent = new EventEmitter(); + + constructor(public service: FirebaseService, private _changeDetectorRef: ChangeDetectorRef) { } + + flip() { + this.service.screenshotResultSummary.isFlipped = + !this.service.screenshotResultSummary.isFlipped; + } + + toggleCollapse() { + this.collapse = !this.collapse; + this.collapseEvent.emit(this.collapse); + } +} diff --git a/tools/screenshot-test/src/app/routes.ts b/tools/screenshot-test/src/app/routes.ts new file mode 100644 index 00000000000..67d097eda11 --- /dev/null +++ b/tools/screenshot-test/src/app/routes.ts @@ -0,0 +1,10 @@ +import {ModuleWithProviders} from '@angular/core'; +import {Routes, RouterModule} from '@angular/router'; +import {ViewerComponent} from './viewer/viewer.component'; + +const SCREENSHOT_ROUTES: Routes = [ + {path: '', component: ViewerComponent, pathMatch: 'full'}, + {path: ':id', component: ViewerComponent} +]; + +export const routing: ModuleWithProviders = RouterModule.forRoot(SCREENSHOT_ROUTES); diff --git a/tools/screenshot-test/src/app/screenshot-result.ts b/tools/screenshot-test/src/app/screenshot-result.ts new file mode 100644 index 00000000000..50a1d9e8405 --- /dev/null +++ b/tools/screenshot-test/src/app/screenshot-result.ts @@ -0,0 +1,58 @@ +const config = require('../config.json'); +/** + * Results for a screenshot test + * Has all related information including Travis Job ID, SHA, pull request number. + * And the test results for each test. + */ +export class ScreenshotResultSummary { + /** PR information: the pull request number */ + prNumber: string; + /** PR information: the sha of the pull request commit */ + sha: string; + /** PR information: The travis job ID */ + travis: string; + + /** The names of the tests that have screenshot results */ + testNames: string[]; + /** + * Test result: passed or failed. The value can be true if test failed but + * PR approved by user + */ + allTestsPassedOrApproved: boolean; + /** Test results: passed or failed for each test */ + testResultsByName: Map = new Map(); + /** + * Test approved: whether the test images are copied to goldens. + * The value is the date/time of approval of current commit. Null if never approved. + */ + approvedTime: number; + + githubStatus: boolean; + + /** Viewing mode, can be flip, diff, side */ + mode: 'diff' | 'side' | 'flip' = 'diff'; + /** When in "Flip" mode, whether the test result or the gold screenshot is being shown. */ + isFlipped: boolean = false; + /** Viewing collapsed: whether the result should be collapsed/expanded */ + collapse: boolean[]; + + setCollapse(value: boolean) { + if (this.collapse) { + for (let i = 0; i < this.collapse.length; i++) { + this.collapse[i] = value; + } + } + } + + get prUrl() { + return `https://github.com/${config.repoSlug}/pull/${this.prNumber}`; + } + + get commitLink() { + return `https://github.com/${config.repoSlug}/commit/${this.sha}`; + } + + get travisLink() { + return `https://travis-ci.org/${config.repoSlug}/jobs/${this.travis}`; + } +} diff --git a/tools/screenshot-test/src/app/viewer/viewer.component.css b/tools/screenshot-test/src/app/viewer/viewer.component.css new file mode 100644 index 00000000000..40dbca3ee94 --- /dev/null +++ b/tools/screenshot-test/src/app/viewer/viewer.component.css @@ -0,0 +1,19 @@ +.mode-section { + display: flex; + flex-direction: column; + margin: 10px 40px 10px 10px; +} + +.description { + font-size: 11px; + color: grey; + padding-left: 20px; +} + +.failed { + color: red; +} + +.passed { + color: forestgreen; +} diff --git a/tools/screenshot-test/src/app/viewer/viewer.component.html b/tools/screenshot-test/src/app/viewer/viewer.component.html new file mode 100644 index 00000000000..8de5f92b50e --- /dev/null +++ b/tools/screenshot-test/src/app/viewer/viewer.component.html @@ -0,0 +1,65 @@ +
+ +

+ + Pull Request: {{screenshotResultSummary.prNumber}} + + + Commit: {{screenshotResultSummary.sha}} + + + Travis: {{screenshotResultSummary.travis}} + +

+

+ + + This will copy all failed test result images to goldens. + Please go to Travis to restart the job manually after approval. + +

+

+ + + + Test images should be the same as golden images. Expand all to verify. + +

+

+ + + {{githubIcon}} + + + refresh + +
+ + This will not update golds, but only change the screenshot test status on current commit. + Once the PR checked in, the golds will be updated automatically. + +

+ + + + +
+ +
+ +
+
diff --git a/tools/screenshot-test/src/app/viewer/viewer.component.ts b/tools/screenshot-test/src/app/viewer/viewer.component.ts new file mode 100644 index 00000000000..709b7c5675f --- /dev/null +++ b/tools/screenshot-test/src/app/viewer/viewer.component.ts @@ -0,0 +1,67 @@ +import {Component, Input} from '@angular/core'; +import {ActivatedRoute} from '@angular/router'; +import {MdSnackBar} from '@angular/material'; +import {FirebaseService} from '../firebase.service'; + +/** + * Component to show test results for one commit. The github status, pull request and travis job + * information, test result and commit SHA are visible. + * User can approve the change by updating the github status, or by updating the goldens. + */ +@Component({ + selector: 'app-viewer', + templateUrl: './viewer.component.html', + styleUrls: ['./viewer.component.css'] +}) +export class ViewerComponent { + messageDuration = {duration: 10000}; + + get isApproved() { + return !!this._service.screenshotResultSummary.approvedTime; + } + + get screenshotResultSummary() { + return this._service.screenshotResultSummary; + } + + get githubIcon(): string { + return this.githubStatus ? 'check' : 'close'; + } + + @Input() + get githubStatus() { + return this.screenshotResultSummary.githubStatus; + } + + get githubClass(): string { + return this.githubStatus ? 'passed' : 'failed'; + } + + constructor(private _service: FirebaseService, + private _route: ActivatedRoute, + public snackBar: MdSnackBar) { + _route.params.subscribe(p => { + this._service.prNumber = p['id']; + }); + } + + approve() { + this._service.approvePullRequest().then((result) => { + this.snackBar.open(`Approved`, '', this.messageDuration); + }).catch((error) => { + this.snackBar.open(`Error ${error}`, '', this.messageDuration); + }); + } + + updateGithubStatus() { + this._service.updatePullRequestResult().then((result) => { + this.snackBar.open(`Approved`, '', this.messageDuration); + }).catch((error) => { + this.snackBar.open(error.message, '', this.messageDuration); + }); + } + + refreshGithubStatus() { + this._service.getGithubStatus(); + } +} diff --git a/tools/screenshot-test/src/config.json b/tools/screenshot-test/src/config.json new file mode 100644 index 00000000000..ed0b0d9a778 --- /dev/null +++ b/tools/screenshot-test/src/config.json @@ -0,0 +1,10 @@ +{ + "firebase": { + "apiKey": "AIzaSyBekh5ZSi1vEhaE2qetH4RU91gHmUmpqgg", + "authDomain": "material2-screenshots.firebaseapp.com", + "databaseURL": "https://material2-screenshots.firebaseio.com", + "storageBucket": "material2-screenshots.appspot.com", + "messagingSenderId": "975527407245" + }, + "repoSlug": "angular/material2" +} diff --git a/tools/screenshot-test/src/environments/environment.prod.ts b/tools/screenshot-test/src/environments/environment.prod.ts new file mode 100644 index 00000000000..3612073bc31 --- /dev/null +++ b/tools/screenshot-test/src/environments/environment.prod.ts @@ -0,0 +1,3 @@ +export const environment = { + production: true +}; diff --git a/tools/screenshot-test/src/environments/environment.ts b/tools/screenshot-test/src/environments/environment.ts new file mode 100644 index 00000000000..00313f16648 --- /dev/null +++ b/tools/screenshot-test/src/environments/environment.ts @@ -0,0 +1,8 @@ +// The file contents for the current environment will overwrite these during build. +// The build system defaults to the dev environment which uses `environment.ts`, but if you do +// `ng build --env=prod` then `environment.prod.ts` will be used instead. +// The list of which env maps to which file can be found in `angular-cli.json`. + +export const environment = { + production: false +}; diff --git a/tools/screenshot-test/src/favicon.ico b/tools/screenshot-test/src/favicon.ico new file mode 100644 index 00000000000..8081c7ceaf2 Binary files /dev/null and b/tools/screenshot-test/src/favicon.ico differ diff --git a/tools/screenshot-test/src/index.html b/tools/screenshot-test/src/index.html new file mode 100644 index 00000000000..dee9b145593 --- /dev/null +++ b/tools/screenshot-test/src/index.html @@ -0,0 +1,16 @@ + + + + + ScreenshotTest + + + + + + + + Loading... + + diff --git a/tools/screenshot-test/src/main.ts b/tools/screenshot-test/src/main.ts new file mode 100644 index 00000000000..11169bab6a5 --- /dev/null +++ b/tools/screenshot-test/src/main.ts @@ -0,0 +1,12 @@ +import './polyfills.ts'; + +import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; +import {enableProdMode} from '@angular/core'; +import {environment} from './environments/environment'; +import {PixactoDashboardModule} from './app/pixacto.dashboard.module'; + +if (environment.production) { + enableProdMode(); +} + +platformBrowserDynamic().bootstrapModule(PixactoDashboardModule); diff --git a/tools/screenshot-test/src/polyfills.ts b/tools/screenshot-test/src/polyfills.ts new file mode 100644 index 00000000000..0f82832ec2c --- /dev/null +++ b/tools/screenshot-test/src/polyfills.ts @@ -0,0 +1,13 @@ +// This file includes polyfills needed by Angular and is loaded before +// the app. You can add your own extra polyfills to this file. +import 'core-js/es6/symbol'; +import 'core-js/es6/object'; +import 'core-js/es6/function'; +import 'core-js/es6/number'; +import 'core-js/es6/string'; +import 'core-js/es6/array'; +import 'core-js/es6/map'; +import 'core-js/es6/reflect'; + +import 'core-js/es7/reflect'; +import 'zone.js/dist/zone'; diff --git a/tools/screenshot-test/src/styles.css b/tools/screenshot-test/src/styles.css new file mode 100644 index 00000000000..524dd109297 --- /dev/null +++ b/tools/screenshot-test/src/styles.css @@ -0,0 +1 @@ +@import '~@angular/material/prebuilt-themes/indigo-pink.css'; diff --git a/tools/screenshot-test/src/tsconfig.json b/tools/screenshot-test/src/tsconfig.json new file mode 100644 index 00000000000..1cf713a384b --- /dev/null +++ b/tools/screenshot-test/src/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "baseUrl": "", + "declaration": false, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": ["es6", "dom"], + "mapRoot": "./", + "module": "es6", + "moduleResolution": "node", + "outDir": "../dist/out-tsc", + "sourceMap": true, + "target": "es5", + "typeRoots": [ + "../node_modules/@types" + ] + } +}