Skip to content

Commit

Permalink
[feat #457] implement configuration, only test changed files again
Browse files Browse the repository at this point in the history
  • Loading branch information
r-hannuschka committed Dec 31, 2021
1 parent d1139bb commit ca56d5c
Show file tree
Hide file tree
Showing 17 changed files with 249 additions and 126 deletions.
5 changes: 4 additions & 1 deletion src/angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,10 @@
"e2e": {
"builder": "@tsmonkeypatch/ngx-builders:playwright",
"options": {
"devServerTarget": "ngx-fileupload-example:serve"
"devServerTarget": "ngx-fileupload-example:serve",
"playwrightConfig": "e2e/playwright.config.js",
"watch": true,
"watchDir": ["e2e/integration"]
},
"configurations": {
"production": {
Expand Down
33 changes: 33 additions & 0 deletions src/e2e/integration/example-2.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { test, expect } from '@playwright/test'

test('test', async ({ page }) => {

// Go to http://localhost:4201/#/dashboard
await page.goto('http://localhost:4200/#/dashboard')

// Click text=Customize
await page.click('text=Customize');
await expect(page).toHaveURL('http://localhost:4200/#/customize')


// Click text=Automatic NgxFileUpload
await page.click('text=Automatic NgxFileUpload');
await expect(page).toHaveURL('http://localhost:4200/#/auto-upload')
// Click text=Typescript
await page.click('text=Typescript');

// Click igx-tab-header[role="tab"]:has-text("Html")
await page.click('igx-tab-header[role="tab"]:has-text("Html")')

// Click text=Validation
await page.click('text=Validation');
await expect(page).toHaveURL('http://localhost:4200/#/validation')

// Click text=Ngx File Drop
await page.click('text=Ngx File Drop');
await expect(page).toHaveURL('http://localhost:4200/#/drop-zone');

// Click text=Ngx Dropzone
await page.click('text=Ngx Dropzone');
await expect(page).toHaveURL('http://localhost:4200/#/ngx-dropzone');
});
14 changes: 7 additions & 7 deletions src/e2e/integration/example.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ import { test, expect } from '@playwright/test'
test('test', async ({ page }) => {

// Go to http://localhost:4201/#/dashboard
await page.goto('http://localhost:4201/#/dashboard');
await page.goto('http://localhost:4200/#/dashboard');

// Click text=Customize
await page.click('text=Customize');
await expect(page).toHaveURL('http://localhost:4201/#/customize');
await expect(page).toHaveURL('http://localhost:4200/#/customize')


// Click text=Automatic NgxFileUpload
await page.click('text=Automatic NgxFileUpload');
await expect(page).toHaveURL('http://localhost:4201/#/auto-upload');

await expect(page).toHaveURL('http://localhost:4200/#/auto-upload')
// Click text=Typescript
await page.click('text=Typescript');

Expand All @@ -21,13 +21,13 @@ test('test', async ({ page }) => {

// Click text=Validation
await page.click('text=Validation');
await expect(page).toHaveURL('http://localhost:4201/#/validation');
await expect(page).toHaveURL('http://localhost:4200/#/validation')

// Click text=Ngx File Drop
await page.click('text=Ngx File Drop');
await expect(page).toHaveURL('http://localhost:4201/#/drop-zone');
await expect(page).toHaveURL('http://localhost:4200/#/drop-zone')

// Click text=Ngx Dropzone
await page.click('text=Ngx Dropzone');
await expect(page).toHaveURL('http://localhost:4201/#/ngx-dropzone');
await expect(page).toHaveURL('http://localhost:4200/#/ngx-dropzone');
});
34 changes: 34 additions & 0 deletions src/e2e/integration/foo/example-2.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { test, expect } from '@playwright/test'

test('test', async ({ page }) => {

// Go to http://localhost:4201/#/dashboard
await page.goto('http://localhost:4200/#/dashboard')


// Click text=Customize
await page.click('text=Customize')
await expect(page).toHaveURL('http://localhost:4200/#/customize')

// Click text=Automatic NgxFileUpload
await page.click('text=Automatic NgxFileUpload');
await expect(page).toHaveURL('http://localhost:4200/#/auto-upload')

// Click text=Typescript
await page.click('text=Typescript')

// Click igx-tab-header[role="tab"]:has-text("Html")
await page.click('igx-tab-header[role="tab"]:has-text("Html")')

// Click text=Validation
await page.click('text=Validation');
await expect(page).toHaveURL('http://localhost:4200/#/validation')

// Click text=Ngx File Drop
await page.click('text=Ngx File Drop');
await expect(page).toHaveURL('http://localhost:4200/#/drop-zone')

// Click text=Ngx Dropzone
await page.click('text=Ngx Dropzone');
await expect(page).toHaveURL('http://localhost:4200/#/ngx-dropzone')
});
16 changes: 16 additions & 0 deletions src/e2e/playwright.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// @ts-check
/** @type {import('@playwright/test').PlaywrightTestConfig} */
module.exports = {
testDir: './integration',
projects: [
{
name: 'Chrome Stable',
use: {
headless: true,
browserName: 'chromium',
// Test against Chrome Stable channel.
channel: 'chrome',
},
},
],
};
3 changes: 2 additions & 1 deletion src/e2e/playwright.conf.ts → src/e2e/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { PlaywrightTestConfig } from '@playwright/test';

const config: PlaywrightTestConfig = {
testDir: './integration',
projects: [
{
name: 'Chrome Stable',
use: {
headless: false,
headless: true,
browserName: 'chromium',
// Test against Chrome Stable channel.
channel: 'chrome',
Expand Down
5 changes: 0 additions & 5 deletions src/projects/builders/builders.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,6 @@
"implementation": "./playwright/index.js",
"schema": "./playwright/schema.json",
"description": "run e2e with playwright"
},
"library": {
"implementation": "./library/library.js",
"schema": "./library/schema.json",
"description": "run e2e with playwright"
}
}
}
40 changes: 0 additions & 40 deletions src/projects/builders/src/library/library.ts

This file was deleted.

Empty file.
14 changes: 0 additions & 14 deletions src/projects/builders/src/library/schema.json

This file was deleted.

21 changes: 21 additions & 0 deletions src/projects/builders/src/playwright/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Angular playwright builder

## Options

```json
"project": {
"root": "e2e/",
"projectType": "application",
"architect": {
"e2e": {
"builder": "@tsmonkeypatch/ngx-builders:playwright",
"options": {
"devServerTarget": "ngx-fileupload-example:serve",
"playwrightConfig": "e2e/playwright.config.ts",
"watch": true,
"watchDir": ["e2e/integration"]
},
},
}
}
```
82 changes: 56 additions & 26 deletions src/projects/builders/src/playwright/index.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,70 @@
import { BuilderOutput, createBuilder, BuilderContext, targetFromTargetString } from '@angular-devkit/architect'
import { BuilderOutput, createBuilder, BuilderContext, targetFromTargetString, BuilderRun } from '@angular-devkit/architect'
import { State } from '@angular-devkit/architect/src/progress-schema';
import { from, Observable, merge } from 'rxjs';
import { filter, switchMap } from 'rxjs/operators';
import { Stats } from 'fs';
import { resolve as pathResolve } from 'path';
import { from, Observable, merge, EMPTY } from 'rxjs';
import { filter, map, shareReplay, switchMap, take, tap } from 'rxjs/operators';
import { FileWatcherService } from './utils/file-watcher';
import { PlaywrightService } from './utils/playwright';

interface PLAYWRIGHT_BUILDER_OPTIONS {
devServerTarget: string
config: string
playwrightConfig: string
watch: boolean
watchDir: string[]
}

function playwrightBuilder(
options: PLAYWRIGHT_BUILDER_OPTIONS,
context: BuilderContext
): Observable<BuilderOutput> {
//start dev server
const fileWatcherService = new FileWatcherService('./e2e')
const playwrightService = new PlaywrightService()

const target = targetFromTargetString(options.devServerTarget)
const server$ = from(context.scheduleTarget(target))

// progress stream from dev server builder
const progress$ = server$.pipe(
switchMap((server) => server.progress),
filter((progress) => progress.state === State.Stopped),
)

return server$.pipe(
// get notified one time if server is running
switchMap((server) => server.result),
// switch to changes on progress or test files
switchMap(() => merge(progress$, fileWatcherService.change())),
// run playwright
switchMap(() => playwrightService.run())
)
): Observable<BuilderOutput> | Promise<BuilderOutput> {

const configPath = pathResolve(context.workspaceRoot, options.playwrightConfig)
const playwrightService = new PlaywrightService(configPath)

let server: BuilderRun | null = null;

// startup
const main$ = from(playwrightService.initialize())
.pipe(
switchMap(() => {
const target = targetFromTargetString(options.devServerTarget)
return context.scheduleTarget(target)
}),
switchMap((builderRun) => {
server = builderRun
return builderRun.result
}),
shareReplay()
)

// watch mode
if (options.watch) {
const fileWatcherService = new FileWatcherService(options.watchDir)
console.dir(options.watchDir)
const progress$ = main$.pipe(
switchMap(() => server?.progress ?? EMPTY),
filter((progress) => progress.state === State.Stopped),
map(() => null)
)

return main$.pipe(
switchMap(() => merge(progress$, fileWatcherService.change())),
switchMap((result: [string, Stats] | null ) => {
const file = result?.[0]
? pathResolve(context.workspaceRoot, result[0])
: void 0

return playwrightService.run(file)
})
)
}

return main$.pipe(
switchMap(() => playwrightService.run()),
tap(() => (server?.stop(), playwrightService.destroy())),
take(1),
).toPromise()
}

// create builder
Expand Down
18 changes: 15 additions & 3 deletions src/projects/builders/src/playwright/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,23 @@
"properties": {
"devServerTarget": {
"type": "string",
"description": "A dev-server-builder target to run test against"
"description": "A dev-server-builder target to run test against",
"default": "@"
},
"config": {
"watch": {
"type": "boolean",
"description": "if set to true it will enable watch mode",
"default": false
},
"watchDir": {
"type": "array",
"description": "array of directories we watch",
"default": ["."]
},
"playwrightConfig": {
"type": "string",
"description": "path to playwright configuration file"
"description": "path to playwright configuration file",
"default": "./playwright.config.ts"
}
}
}
16 changes: 7 additions & 9 deletions src/projects/builders/src/playwright/utils/file-watcher.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
import { FSWatcher, watch } from 'chokidar';
import { Stats } from 'fs';
import { Observable, fromEventPattern } from 'rxjs';
import { switchMap } from 'rxjs/operators';

export class FileWatcherService {
private filePath: string[];
private watch$: Observable<unknown> | null = null;
private watch$: Observable<[string, Stats]> | null = null;

constructor(path: string | string[]) {
this.filePath = Array.isArray(path) ? path : [path];
}
constructor(private readonly directories: string[]) {}

change(): Observable<unknown> {
change(): Observable<[string, Stats]> {
if (!this.watch$) {
this.watch$ = this.initializeWatcher()
}
return this.watch$
}

private initializeWatcher(): Observable<unknown> {
const watcher = watch(this.filePath)
const change$ = fromEventPattern(this.createHandler(watcher, 'change'))
private initializeWatcher(): Observable<[string, Stats]> {
const watcher = watch(this.directories)
const change$ = fromEventPattern<[string, Stats]>(this.createHandler(watcher, 'change'))
const ready$ = fromEventPattern(this.createHandler(watcher, 'ready'))

return ready$.pipe(switchMap(() => change$))
Expand Down

0 comments on commit ca56d5c

Please sign in to comment.