-
Notifications
You must be signed in to change notification settings - Fork 0
feat(Core): create initial core package #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
base: master
Are you sure you want to change the base?
Changes from 5 commits
6d209de
8cf71e2
296b015
f28d3f2
17cb915
9a9e95b
f0811b0
6383233
7e47fb3
11f2d9f
4cdb45f
3fcca6d
cf2545b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,2 @@ | ||
| pnpm test | ||
| pnpm lint | ||
| pnpm typecheck |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| #!/usr/bin/env node | ||
|
|
||
| import { runTestsCLI } from "./runner"; | ||
|
|
||
| const args = process.argv.slice(2); | ||
| const patternArg = args[0] ? new RegExp(args[0]) : undefined; | ||
|
ElijahKotyluk marked this conversation as resolved.
|
||
|
|
||
| runTestsCLI({ pattern: patternArg }).catch((err) => { | ||
| console.error(err); | ||
| process.exit(1); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| import { Suite } from "./suite"; | ||
|
|
||
| interface OnyxGlobalContext { | ||
| currentSuite: Suite | null; | ||
| } | ||
| const onyxGlobalContext: OnyxGlobalContext = { | ||
| currentSuite: null, | ||
| }; | ||
|
|
||
| export { onyxGlobalContext, type OnyxGlobalContext }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| import { | ||
| MatcherContext, | ||
| MatcherFn, | ||
| MatcherMap, | ||
| matcherRegistry, | ||
| } from "./matchers"; | ||
|
|
||
| export interface ExpectInterface { | ||
| <T>(value: T): Expectation<T>; | ||
| extend<M extends MatcherMap>(m: M): void; | ||
| } | ||
|
|
||
| type Expectation<T> = { | ||
| not: Expectation<T>; | ||
| } & { | ||
| [K in keyof typeof matcherRegistry]: (typeof matcherRegistry)[K] extends MatcherFn< | ||
| T, | ||
| infer A | ||
| > | ||
| ? (...args: A) => ReturnType<(typeof matcherRegistry)[K]> | ||
| : never; | ||
| }; | ||
|
|
||
| export function extendMatchers(newMatchers: MatcherMap) { | ||
| for (const key in newMatchers) { | ||
| matcherRegistry[key] = newMatchers[key]; | ||
| } | ||
| } | ||
|
|
||
| export const expect: ExpectInterface = (function () { | ||
| function expectFn<T>(received: T): Expectation<T> { | ||
| function makeExpectation(isNot: boolean): Expectation<T> { | ||
| const ctx: MatcherContext = { | ||
| isNot, | ||
| diff(a, b) { | ||
| return ( | ||
| JSON.stringify(a, null, 2) + "\nvs\n" + JSON.stringify(b, null, 2) | ||
| ); | ||
| }, | ||
| }; | ||
|
|
||
| const handler: Record<string, unknown> = {}; | ||
|
|
||
| for (const name in matcherRegistry) { | ||
| const fn = matcherRegistry[name] as MatcherFn<T>; | ||
|
|
||
| handler[name] = (...args: unknown[]) => | ||
| fn.call(ctx, received, ...(args as [])); | ||
| } | ||
|
|
||
| return new Proxy(handler as Expectation<T>, { | ||
| get(target, prop) { | ||
| if (prop === "not") { | ||
| return makeExpectation(!isNot); | ||
| } | ||
| return target[prop as keyof typeof target]; | ||
| }, | ||
| }); | ||
| } | ||
|
|
||
| return makeExpectation(false); | ||
| } | ||
|
|
||
| (expectFn as ExpectInterface).extend = extendMatchers; | ||
|
|
||
| return expectFn as ExpectInterface; | ||
| })(); | ||
|
|
||
| expect.extend = extendMatchers; | ||
| Object.defineProperty(expect, "matchers", { | ||
| get() { | ||
| return matcherRegistry; | ||
| }, | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| import { getCurrentSuite } from "./suite"; | ||
| import { PromisableFn } from "./types"; | ||
|
|
||
| type HookFn = PromisableFn<void>; | ||
|
|
||
| type Hook = Array<HookFn>; | ||
|
|
||
| interface Hooks { | ||
| beforeAll: Hook; | ||
| afterAll: Hook; | ||
| beforeEach: Hook; | ||
| afterEach: Hook; | ||
| } | ||
|
|
||
| type HookName = keyof Hooks; | ||
|
|
||
| function beforeAll(...hooks: HookFn[]): void { | ||
| getCurrentSuite().beforeAllHooks.push(...hooks); | ||
| } | ||
| function afterAll(...hooks: HookFn[]): void { | ||
| getCurrentSuite().afterAllHooks.push(...hooks); | ||
| } | ||
| function beforeEach(...hooks: HookFn[]): void { | ||
| getCurrentSuite().beforeEachHooks.push(...hooks); | ||
| } | ||
|
|
||
| function afterEach(...hooks: HookFn[]): void { | ||
| getCurrentSuite().afterEachHooks.push(...hooks); | ||
| } | ||
|
|
||
| export { | ||
| beforeAll, | ||
| afterAll, | ||
| beforeEach, | ||
| afterEach, | ||
| type Hooks, | ||
| type HookName, | ||
| type Hook, | ||
| type HookFn, | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,2 @@ | ||
| console.log("Core package"); | ||
| export { expect } from "./expect"; | ||
| export { describe, it } from "./interface"; |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,33 @@ | ||||||||||||||||||||||||||||||||||||||
| import { onyxGlobalContext } from "./context"; | ||||||||||||||||||||||||||||||||||||||
| import { getCurrentSuite, Suite } from "./suite"; | ||||||||||||||||||||||||||||||||||||||
| import { Test } from "./test"; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| import type { PromisableFn } from "./types"; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| function _describe(description: string, fn: PromisableFn<void>) { | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
| const parent = getCurrentSuite(); | ||||||||||||||||||||||||||||||||||||||
| const suite = new Suite(description, parent); | ||||||||||||||||||||||||||||||||||||||
| parent.addSuite(suite); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| onyxGlobalContext.currentSuite = suite; | ||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||
| fn(); | ||||||||||||||||||||||||||||||||||||||
| } finally { | ||||||||||||||||||||||||||||||||||||||
| onyxGlobalContext.currentSuite = parent; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
ElijahKotyluk marked this conversation as resolved.
|
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| function _it(description: string, fn: PromisableFn<void>) { | ||||||||||||||||||||||||||||||||||||||
| const test = new Test(description, fn); | ||||||||||||||||||||||||||||||||||||||
| getCurrentSuite().addTest(test); | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| const describe = (description: string, fn: PromisableFn<void>) => { | ||||||||||||||||||||||||||||||||||||||
| return _describe(description, fn); | ||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| const it = (description: string, fn: PromisableFn<void>) => { | ||||||||||||||||||||||||||||||||||||||
| return _it(description, fn); | ||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| export { describe, it }; | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+25
to
+33
|
||||||||||||||||||||||||||||||||||||||
| const describe = (description: string, fn: PromisableFn<void>) => { | |
| return _describe(description, fn); | |
| }; | |
| const it = (description: string, fn: PromisableFn<void>) => { | |
| return _it(description, fn); | |
| }; | |
| export { describe, it }; | |
| export { _describe as describe, _it as it }; |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,38 @@ | ||||||
| import { extendMatchers } from "./expect"; | ||||||
|
|
||||||
| export interface MatcherMap { | ||||||
| [name: string]: MatcherFn<unknown>; | ||||||
| } | ||||||
|
|
||||||
| export const coreMatchers: MatcherMap = {}; | ||||||
|
|
||||||
| export const matcherRegistry: MatcherMap = { ...coreMatchers }; | ||||||
|
|
||||||
| extendMatchers({ | ||||||
| toBe<T>(this: MatcherContext, received: T, expected: T) { | ||||||
| const pass = Object.is(received, expected); | ||||||
| if (this.isNot ? pass : !pass) { | ||||||
| throw new Error( | ||||||
| `Expected ${received} ${this.isNot ? "not " : ""}to be ${expected}`, | ||||||
| ); | ||||||
| } | ||||||
| }, | ||||||
|
|
||||||
| toEqual<T>(this: MatcherContext, received: T, expected: T) { | ||||||
| const pass = JSON.stringify(received) === JSON.stringify(expected); | ||||||
|
ElijahKotyluk marked this conversation as resolved.
|
||||||
| const pass = JSON.stringify(received) === JSON.stringify(expected); | |
| const pass = deepEqual(received, expected); |
Uh oh!
There was an error while loading. Please reload this page.