Skip to content

Commit

Permalink
feat(cli): migrate to lh v11
Browse files Browse the repository at this point in the history
BREAKING CHANGES: 
- migrate to esm requires user-flows to be .mts instead of .ts
- migration to v11 means budgets are no longer supported
  • Loading branch information
ChristopherPHolder authored Aug 26, 2024
2 parents 4382e97 + b8b8f5b commit ae3f82e
Show file tree
Hide file tree
Showing 280 changed files with 23,026 additions and 34,851 deletions.
17 changes: 11 additions & 6 deletions .github/workflows/user-flow-md-report-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,25 @@ jobs:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup node ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
cache: 'npm'
node-version: ${{ matrix.node-version }}
- name: install

- name: Clean Install
run: npm ci
- name: build
run: npm run nx -- affected:build --base=origin/main --head=HEAD
- name: run
run: npm run md-report-test

- name: Collect Report
run: npm run @push-based/user-flow -- --rcPath ./examples/github-report/.user-flowrc.json --openReport false

- name: Rename Report
run: npx tsx --tsconfig ./examples/github-report/tsconfig.json ./examples/github-report/tools/md-report-rename.mts

- name: Add reduced report as comment to the PR
uses: marocchino/sticky-pull-request-comment@v2
with:
hide_and_recreate: true
header: md-report-test
path: ./dist/user-flow/user-flow-gh-integration/md-report.md
path: ./examples/github-report/measures/md-report.md
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ testem.log
.DS_Store
Thumbs.db

.nx/cache
.nx

.env
.code-pushup

examples/**/measures/*
3 changes: 2 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
/dist
/coverage

/.nx/cache
/.nx/cache
/.nx/workspace-data
28 changes: 28 additions & 0 deletions .verdaccio/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# path to a directory with all packages
storage: ../tmp/local-registry/storage

# a list of other known repositories we can talk to
uplinks:
npmjs:
url: https://registry.npmjs.org/
maxage: 60m

packages:
'**':
# give all users (including non-authenticated users) full access
# because it is a local registry
access: $all
publish: $all
unpublish: $all

# if package is not available locally, proxy requests to npm registry
proxy: npmjs

# log settings
log:
type: stdout
format: pretty
level: warn

publish:
allow_offline: true # set offline to true to allow publish offline
38 changes: 9 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ In addition, it is always up-to-date with the latest Chrome DevTools features.
-[Run it in your CI ](https://github.com/push-based/user-flow#github-workflow-integration-of-lighthouse-user-flows-in-your-pr)
-[Execute ChromeDevTools recorder exports](https://github.com/push-based/user-flow#working-with-devtools-recorder-exports)
- 🏃‍♀️ Measure Runtime performance
- 🔒 [Performance budgets](https://github.com/push-based/user-flow#performance-budgets)
- 🦮 Zero setup cost
- 🤓 Excellent DX through `--dryRun` and friends
- ⚙ Nx plugin [user-flow-nx-plugin]() to generate/execute/migrate lighthouse user flows
Expand Down Expand Up @@ -103,11 +102,11 @@ _./.user-flowrc.json_
}
```

2. The CLI automatically creates an example user-flow. (`./user-flows/basic-navigation.uf.ts`)
2. The CLI automatically creates an example user-flow. (`./user-flows/basic-navigation.uf.mts`)

It is a simple navigation measurement to start from.

_./basic-navigation.uf.ts_
_./basic-navigation.uf.mts_
```typescript
import {
UserFlowInteractionsFn,
Expand All @@ -122,17 +121,15 @@ const interactions: UserFlowInteractionsFn = async (ctx: UserFlowContext): Promi

// Navigate to URL
await flow.navigate(url, {
stepName: `Navigate to ${url}`,
name: `Navigate to ${url}`,
});

};

const userFlowProvider: UserFlowProvider = {
flowOptions: {name: 'Order Coffee'},
interactions
};

module.exports = userFlowProvider;
export default {
flowOptions: { name: "Order Coffee" },
interactions,
} satisfies UserFlowProvider;
```

3. Run CLI
Expand All @@ -147,7 +144,7 @@ This will execute the user flow and opens the HTML report in the browser:

For more information on how to write user-flows read in the [Writing user flows for the CLI](https://github.com/push-based/user-flow/blob/main/packages/cli/docs/writing-basic-user-flows.md) section.

Optionally you can pass params to overwrite the values form `.user-flowrc.ts` in the file directly or over the CLI:
Optionally you can pass params to overwrite the values form `.user-flowrc.json` in the file directly or over the CLI:

```bash
npx user-flow --ufPath=./user-flows-new --outPath=./user-flows-reports --url=https://localhost:4200
Expand Down Expand Up @@ -192,8 +189,6 @@ This command helps you to set up a `.user-flowrc.json` and asks for input over C
| ---------------------------------- | --------- | ---------------------- |----------------------------------------------------------------------------------------------------------|
| **`-h`**, **`--generateFlow`** | `boolean` | n/a | Generate basic user-flow file under `ufPath` |
| **`-g`**, **`--generateGhWorkflow`** | `boolean` | n/a | Generate `user-flow.yml` file under `.github/workflows` |
| **`-x`**, **`--generateBudgets`** | `boolean` | n/a | Generate `budget.json` file under the current working directury |
| **`--lhr`** | `string` | n/a | Used together with `--generateBudgets`. Path to lighthouse report for initial budget |

<img width="960" alt="getting-started-resulting-navigation-report" src="https://user-images.githubusercontent.com/10064416/168185483-c6ca499e-a8a6-40b7-b450-448de8784454.PNG">

Expand All @@ -214,9 +209,8 @@ This command executes a set of user-flow definitions against the target URL and
| Option | Type | Default | Description |
|------------------------------------|-----------|------------------------|---------------------------------------------------------------------------------------------------------|
| **`-t`**, **`--url`** | `string` | n/a | URL to analyze |
| **`-u`**, **`--ufPath`** | `string` | `./user-flows` | Path to user-flow file or folder containing user-flow files to run. (`*.uf.ts` or`*.uf.js`) |
| **`-u`**, **`--ufPath`** | `string` | `./user-flows` | Path to user-flow file or folder containing user-flow files to run. (`*.uf.mts` or`*.uf.js`) |
| **`-c`**, **`--configPath`** | `string` | n/a | Path to the lighthouse `config.json` file |
| **`-b`**, **`--budgetPath`** | `string` | n/a | Path to the lighthouse `budget.json` file |
| **`-s`**, **`--serveCommand`** | `string` | n/a | Runs a npm script to serve the target app. This has to be used in combination with `--awaitServeStdout` |
| **`-a`**, **`--awaitServeStdout`** | `string` | `.user-flowrc` setting | Waits for stdout from the serve command to start collecting user-flows |
| **`-f`**, **`--format`** | `string` | `html`, `json` setting | Format of the creates reports ( `html`, `json`, `md`, `stdout`) |
Expand Down Expand Up @@ -279,20 +273,6 @@ This library provides a way to replay and enrich those interactions over the CLI

See [recorder-exports](https://github.com/push-based/user-flow/blob/main/packages/cli/docs/recorder-exports.md) for more details.

## [Performance Budgets](https://github.com/push-based/user-flow/blob/main/packages/cli/docs/performance-budgets.md)

Implementing performance improvements without breaking something is hard.
**Even harder is it, to keep it that way. 🔒**

![img-budgets-mode-support](https://user-images.githubusercontent.com/10064416/164581870-3534f8b0-b7c1-4252-9f44-f07febaa7359.PNG)

Automatically create budgets with:
`npx user-flow init --generateBudgets`
Automatically create budgets from an existing lhr with:
`npx user-flow init --generateBudgets --lhr path/to/lhr.json`

See [performance-budgets](https://github.com/push-based/user-flow/blob/main/packages/cli/docs/performance-budgets.md) for more details.

## [GitHub workflow integration of lighthouse user flows in your PR](https://github.com/push-based/user-flow/blob/main/packages/cli/docs/github-workflow-integration.md)

With just a few steps you can run your user flows in as a GitHub workflow to enrich your PR's with report summaries as
Expand Down
File renamed without changes.
21 changes: 21 additions & 0 deletions e2e/cli-e2e/mocks/user-flows/basic-navigation.uf.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// @ts-ignore // This is a mock file!
import { UserFlowContext, UserFlowInteractionsFn, UserFlowProvider } from '@push-based/user-flow';

const interactions: UserFlowInteractionsFn = async (ctx: UserFlowContext): Promise<any> => {
const { flow, collectOptions } = ctx;
const { url } = collectOptions;

await flow.navigate(url, {
name: `Navigate to ${url}`,
});

// ℹ Tip:
// Read more about the other measurement modes here:
// https://github.com/push-based/user-flow/blob/main/packages/cli/docs/writing-basic-user-flows.md

};

export default {
flowOptions: {name: 'Basic Navigation Example'},
interactions
} satisfies UserFlowProvider;
25 changes: 25 additions & 0 deletions e2e/cli-e2e/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "cli-e2e",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "e2e/cli-e2e/src",
"projectType": "application",
"targets": {
"lint": {
"executor": "@nx/linter:eslint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["e2e/cli-e2e/**/*.ts"]
}
},
"test": {
"executor": "@nx/vite:test",
"options": {
"config": "e2e/cli-e2e/vite.config.e2e.mts"
}
}
},
"implicitDependencies": [
"cli"
],
"tags": ["type:e2e"]
}
135 changes: 135 additions & 0 deletions e2e/cli-e2e/setup.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import { afterAll, beforeAll, beforeEach, afterEach } from 'vitest';

import { cpSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
import { join, normalize, sep } from 'node:path';

import { CliTest, E2E_DIR, normalizePath } from './utils/setup';
import { spawn } from 'node:child_process';

const ANSI_ESCAPE_REGEX = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;

function filePath(p: string): string {
const paths = normalizePath(p).split(sep);
return paths.splice(0, paths.length - 1).join();
}

beforeAll((ctx) => {
mkdirSync(join(E2E_DIR, filePath(ctx.name)), { recursive: true });
});

beforeEach<CliTest>((ctx) => {
ctx.root = join(E2E_DIR, filePath(ctx.task.file.name), normalizePath(join(ctx.task.suite.name, ctx.task.name)));

ctx.setupFns = {
setupRcJson: (rc: {}, rcName= `.user-flowrc.json`) => {
writeFileSync(
join(ctx.root, rcName),
JSON.stringify(rc, null, 4),
{ encoding: 'utf8' }
);
},
setupUserFlows: (mockUserFlow: string, userFlowDir = 'user-flows') => {
cpSync(mockUserFlow, join(ctx.root, userFlowDir, normalize(mockUserFlow).split(sep).at(-1)))
}
}

mkdirSync(ctx.root, { recursive: true });
});

export type CliProcessResult = {
stdout: string;
stderr: string;
code: number | null;
}

beforeEach<CliTest>((ctx) => {
ctx.cli = {} as any;
ctx.cli.stdout = '';
ctx.cli.stderr = '';
ctx.cli.code = null;


ctx.cli.run = (command: string, args: string[] = [], waitForClose = true) => new Promise<CliProcessResult>((resolve) => {
ctx.cli.process = spawn(command, args, { stdio: 'pipe', shell: true, cwd: ctx.root });

ctx.cli.process.stdout.on('data', (data) => {
const stdout = String(data).replace(ANSI_ESCAPE_REGEX, '');

if (ctx.cli.verbose) {
console.log(stdout);
}

ctx.cli.stdout += stdout;
});


ctx.cli.process.stderr.on('data', (data) => {
const stderr = String(data).replace(ANSI_ESCAPE_REGEX, '');

if (ctx.cli.verbose) {
console.log(stderr);
}

ctx.cli.stderr += stderr;
});


ctx.cli.process.on('close', code => {
ctx.cli.code = code;

if (ctx.cli.verbose) {
console.log(code);
}

resolve({
stdout: ctx.cli.stdout,
stderr: ctx.cli.stderr,
code: ctx.cli.code
});
});

if (!waitForClose) {
resolve({
stdout: ctx.cli.stdout,
stderr: ctx.cli.stderr,
code: ctx.cli.code
});
}
});

ctx.cli.waitForStdout = (expectedStdout: string) => {
return new Promise((resolve) => {
ctx.cli.process.stdout.on('data', (data) => {
const stdout = String(data).replace(ANSI_ESCAPE_REGEX, '');
if (stdout.includes(expectedStdout)) {
resolve();
}
});
});
};

ctx.cli.waitForClose = () => {
return new Promise((resolve) => {
ctx.cli.process.on('close', (code) => {
ctx.cli.code = code;
resolve({
stdout: ctx.cli.stdout,
stderr: ctx.cli.stderr,
code: ctx.cli.code
});
});
});
};

ctx.cli.type = (inputs: string) => {
ctx.cli.process.stdin.write(inputs);
};
});

afterEach<CliTest>((ctx) => {
rmSync(ctx.root, { recursive: true });
});

afterAll((ctx) => {
rmSync(join(E2E_DIR, filePath(ctx.name)), { recursive: true });
});
Loading

0 comments on commit ae3f82e

Please sign in to comment.