Skip to content

Commit

Permalink
Merge pull request #2 from phryneas/kcd-scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
phryneas authored Oct 10, 2024
2 parents 036fbc0 + 0f7cf17 commit 67a3e4e
Show file tree
Hide file tree
Showing 20 changed files with 8,741 additions and 1,933 deletions.
2 changes: 2 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
tsup.config.ts
dist/
18 changes: 18 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module.exports = {
extends: 'kentcdodds',
rules: {
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-empty-interface': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/unified-signatures': 'off',
'@typescript-eslint/no-unused-vars': [
'error',
{
args: 'after-used',
argsIgnorePattern: '^_',
ignoreRestSiblings: true,
varsIgnorePattern: '^_',
},
],
},
}
2 changes: 2 additions & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# format with kcd-scripts
325d59e3cd0bf4c7ab738381e1bb49aef3bc7363
4 changes: 2 additions & 2 deletions .github/workflows/pkg-pr-new-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ on:
pull_request:
push:
branches:
- "**"
- '**'
tags:
- "!**"
- '!**'

jobs:
prerelease:
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ dist/
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
!.yarn/versions
*.tsbuildinfo
1 change: 1 addition & 0 deletions .prettierrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require("kcd-scripts/prettier.js");
13 changes: 11 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"@types/react": "^18",
"@types/react-dom": "^18",
"expect": "^29.7.0",
"kcd-scripts": "^16.0.0",
"pkg-pr-new": "^0.0.29",
"prettier": "^3.3.3",
"publint": "^0.2.11",
Expand All @@ -79,7 +80,15 @@
"build": "tsup",
"pkg-pr-new-publish": "yarn build && pkg-pr-new publish --no-template",
"prepack": "yarn build",
"verify": "attw --pack . && publint"
"format": "kcd-scripts format",
"lint": "kcd-scripts lint --config .eslintrc.cjs",
"test": "kcd-scripts test --passWithNoTests",
"verify": "attw --pack . && publint",
"typecheck": "kcd-scripts typecheck --build",
"validate": "CI=true kcd-scripts validate verify,lint,typecheck,test"
},
"packageManager": "[email protected]"
"packageManager": "[email protected]",
"resolutions": {
"eslint-config-kentcdodds": "^21.0.0"
}
}
14 changes: 7 additions & 7 deletions src/assertable.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { RenderStream } from "./renderStream/createRenderStream.js";
import {type RenderStream} from './renderStream/createRenderStream.js'

export const assertableSymbol = Symbol.for(
"@testing-library/react-render-stream:assertable"
);
'@testing-library/react-render-stream:assertable',
)

/**
* A function or object that can be used in assertions, like e.g.
Expand All @@ -13,14 +13,14 @@ export const assertableSymbol = Symbol.for(
```
*/
export type Assertable = {
[assertableSymbol]: RenderStream<any>;
};
[assertableSymbol]: RenderStream<any>
}

export function markAssertable<T extends {}>(
assertable: T,
stream: RenderStream<any>
stream: RenderStream<any>,
): T & Assertable {
return Object.assign(assertable, {
[assertableSymbol]: stream,
});
})
}
16 changes: 8 additions & 8 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@ export type {
RenderStream,
RenderStreamWithRenderFn,
RenderStreamOptions,
} from "./renderStream/createRenderStream.js";
} from './renderStream/createRenderStream.js'
export {
createRenderStream,
useTrackRenders,
WaitForRenderTimeoutError,
} from "./renderStream/createRenderStream.js";
} from './renderStream/createRenderStream.js'

export type { SyncScreen } from "./renderStream/Render.js";
export type {SyncScreen} from './renderStream/Render.js'

export { renderToRenderStream } from "./renderToRenderStream.js";
export type { RenderStreamWithRenderResult } from "./renderToRenderStream.js";
export { renderHookToSnapshotStream } from "./renderHookToSnapshotStream.js";
export type { SnapshotStream } from "./renderHookToSnapshotStream.js";
export {renderToRenderStream} from './renderToRenderStream.js'
export type {RenderStreamWithRenderResult} from './renderToRenderStream.js'
export {renderHookToSnapshotStream} from './renderHookToSnapshotStream.js'
export type {SnapshotStream} from './renderHookToSnapshotStream.js'

export type { Assertable } from "./assertable.js";
export type {Assertable} from './assertable.js'
13 changes: 9 additions & 4 deletions src/jest/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import { expect } from "@jest/globals";
import { toRerender, toRenderExactlyTimes } from "./renderStreamMatchers.js";
import type { RenderStreamMatchers } from "./renderStreamMatchers.js";
import {expect} from '@jest/globals'
import {
toRerender,
toRenderExactlyTimes,
type RenderStreamMatchers,
} from './renderStreamMatchers.js'

expect.extend({
toRerender,
toRenderExactlyTimes,
});
})

declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace jest {
// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface Matchers<R = void, T = {}> extends RenderStreamMatchers<R, T> {}
}
}
96 changes: 51 additions & 45 deletions src/jest/renderStreamMatchers.ts
Original file line number Diff line number Diff line change
@@ -1,104 +1,110 @@
import type { MatcherFunction } from "expect";
import { WaitForRenderTimeoutError } from "@testing-library/react-render-stream";
import type {
Assertable,
NextRenderOptions,
RenderStream,
} from "@testing-library/react-render-stream";
import {MatcherContext, type MatcherFunction} from 'expect'
import {
WaitForRenderTimeoutError,
type Assertable,
type NextRenderOptions,
type RenderStream,
} from '@testing-library/react-render-stream'
// explicitly imported the symbol from the internal file
// this will bundle the `Symbol.for` call twice, but we keep it private
import { assertableSymbol } from "../assertable.js";
import {assertableSymbol} from '../assertable.js'

export interface RenderStreamMatchers<R = void, T = {}> {
toRerender: T extends RenderStream<any> | Assertable
? (options?: NextRenderOptions) => Promise<R>
: {
error: "matcher needs to be called on a `takeRender` function, `takeSnapshot` function or `RenderStream` instance";
};
error: 'matcher needs to be called on a `takeRender` function, `takeSnapshot` function or `RenderStream` instance'
}

toRenderExactlyTimes: T extends RenderStream<any> | Assertable
? (count: number, options?: NextRenderOptions) => Promise<R>
: {
error: "matcher needs to be called on a `takeRender` function, `takeSnapshot` function or `RenderStream` instance";
};
error: 'matcher needs to be called on a `takeRender` function, `takeSnapshot` function or `RenderStream` instance'
}
}

export const toRerender: MatcherFunction<[options?: NextRenderOptions]> =
async function (actual, options) {
const _stream = actual as RenderStream<any> | Assertable;
async function toRerender(this: MatcherContext, actual, options) {
const _stream = actual as RenderStream<any> | Assertable
const stream =
assertableSymbol in _stream ? _stream[assertableSymbol] : _stream;
const hint = this.utils.matcherHint("toRerender");
let pass = true;
assertableSymbol in _stream ? _stream[assertableSymbol] : _stream
const hint = this.utils.matcherHint('toRerender')
let pass = true
try {
await stream.peekRender({ timeout: 100, ...options });
await stream.peekRender({timeout: 100, ...options})
} catch (e) {
if (e instanceof WaitForRenderTimeoutError) {
pass = false;
pass = false
} else {
throw e;
throw e
}
}

return {
pass,
message() {
return (
hint +
`\n\nExpected component to${pass ? " not" : ""} rerender, ` +
`but it did${pass ? "" : " not"}.`
);
`${hint}\n\nExpected component to${pass ? ' not' : ''} rerender, ` +
`but it did${pass ? '' : ' not'}.`
)
},
};
};
}
}

/** to be thrown to "break" test execution and fail it */
const failed = {};
const failed = new Error()

export const toRenderExactlyTimes: MatcherFunction<
[times: number, options?: NextRenderOptions]
> = async function (actual, times, optionsPerRender) {
const _stream = actual as RenderStream<any> | Assertable;
> = async function toRenderExactlyTimes(
this: MatcherContext,
actual,
times,
optionsPerRender,
) {
const _stream = actual as RenderStream<any> | Assertable
const stream =
assertableSymbol in _stream ? _stream[assertableSymbol] : _stream;
const options = { timeout: 100, ...optionsPerRender };
const hint = this.utils.matcherHint("toRenderExactlyTimes");
let pass = true;
assertableSymbol in _stream ? _stream[assertableSymbol] : _stream
const options = {timeout: 100, ...optionsPerRender}
const hint = this.utils.matcherHint('toRenderExactlyTimes')
let pass = true
try {
if (stream.totalRenderCount() > times) {
throw failed;
throw failed
}
try {
while (stream.totalRenderCount() < times) {
await stream.waitForNextRender(options);
// eslint-disable-next-line no-await-in-loop
await stream.waitForNextRender(options)
}
} catch (e) {
// timeouts here should just fail the test, rethrow other errors
throw e instanceof WaitForRenderTimeoutError ? failed : e;
throw e instanceof WaitForRenderTimeoutError ? failed : e
}
try {
await stream.waitForNextRender(options);
await stream.waitForNextRender(options)
} catch (e) {
// we are expecting a timeout here, so swallow that error, rethrow others
if (!(e instanceof WaitForRenderTimeoutError)) {
throw e;
throw e
}
}
} catch (e) {
if (e === failed) {
pass = false;
pass = false
} else {
throw e;
throw e
}
}
return {
pass,
message() {
return (
hint +
` Expected component to${pass ? " not" : ""} render exactly ${times}.` +
`${
hint
} Expected component to${pass ? ' not' : ''} render exactly ${times}.` +
` It rendered ${stream.totalRenderCount()} times.`
);
)
},
};
};
}
}
Loading

0 comments on commit 67a3e4e

Please sign in to comment.