Skip to content

use kcd-scripts #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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": "yarn@4.5.0"
"packageManager": "yarn@4.5.0",
"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