Skip to content

Commit 03aed66

Browse files
committed
Remove Effection and get (most) tests passing for CLI
1 parent 92a6a92 commit 03aed66

File tree

13 files changed

+54
-110
lines changed

13 files changed

+54
-110
lines changed

.github/workflows/test.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,6 @@ jobs:
1313
- uses: denoland/setup-deno@v2
1414
with:
1515
deno-version: v2.x
16-
- run: deno test -A
16+
- run: |
17+
deno run -A packages/cli/src/main.ts build
18+
deno test -A

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@
66
.netlify
77

88
.vscode
9+
/build/

deno.lock

Lines changed: 0 additions & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/cli/test/agent.test.html

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@
2525
<body>
2626

2727
<!-- Add your site or application content here -->
28-
<p>Hello world! This is HTML5 Boilerplate.</p>
28+
<p id="hello">Hello world! This is HTML5 Boilerplate.</p>
29+
<section id="facts">
30+
<h1 id="fact1">Interactors == Awesome</h1>
31+
</section>
2932
<script src="../build/agent.js"></script>
3033

3134
</body>

packages/cli/test/agent.test.ts

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { afterEach, beforeEach, describe, it } from "jsr:@std/testing/bdd";
22
import { expect } from "jsr:@std/expect";
33
import { type Browser, chromium } from "playwright";
4-
import { HTML as $HTML } from "@interactors/html";
4+
import { HTML as $HTML, Heading as $Heading, matching } from "@interactors/html";
55
import { Ok } from "effection";
66

77
const HTML = $HTML.builder((i) => i);
8+
const Heading = $Heading.builder(i => i);
89

910
let browser: Browser;
1011
let agent = {
@@ -52,8 +53,8 @@ describe("Interactor Agent", () => {
5253
});
5354

5455
it("can call nested interactors", async function () {
55-
const interaction = HTML({ title: "greeting" })
56-
.find(HTML("Hello world! This is HTML5 Boilerplate."))
56+
const interaction = HTML({ id: "facts" })
57+
.find(HTML("Interactors == Awesome"))
5758
.exists();
5859
const result = await agent.run(interaction);
5960
expect(result).toEqual({ ok: true });
@@ -69,18 +70,15 @@ describe("Interactor Agent", () => {
6970
),
7071
).toEqual({ ok: true });
7172
expect(
72-
await agent.run(HTML({ id: "hello" }).has({ text: "Goodbye world!" })),
73+
await agent.run(HTML({ id: "hello" }).has({ text: "Hello world! This is HTML Boilerplate." })),
7374
).toMatchObject({
7475
ok: false,
7576
});
7677
});
7778

78-
// it('can make assertions based on matchers', async function () {
79-
80-
// expect(await agent.run(HTML({ id: matching(/hel/) }).has({ text: matching(/Hello world!/) }))).toEqual({
81-
// ok: true
82-
// });
83-
// });
84-
85-
it.skip("can validate that a set of interactions can be run ahead of time", () => {});
79+
it.skip('can make assertions based on matchers', async function () {
80+
expect(await agent.run(HTML({ id: matching(/hel/) }).has({ text: matching(/Hello world!/) }))).toEqual({
81+
ok: true
82+
});
83+
});
8684
});

packages/core/deno.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
},
88
"exports": "./mod.ts",
99
"imports": {
10-
"@effection/core": "npm:@effection/[email protected]",
1110
"@std/expect": "jsr:@std/expect@^1.0.8",
1211
"@std/testing": "jsr:@std/testing@^1.0.5",
1312
"@testing-library/dom": "npm:@testing-library/dom@^8.18.1",

packages/core/src/converge.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
1-
import { type Operation, sleep } from '@effection/core';
2-
import { performance } from 'performance-api';
3-
import { globals } from '@interactors/globals'
1+
import { performance } from "performance-api";
2+
import { globals } from "@interactors/globals";
43

5-
export function* converge<T>(fn: () => T): Operation<T> {
4+
export async function converge<T>(fn: () => T): Promise<T> {
65
let startTime = performance.now();
7-
while(true) {
6+
while (true) {
87
try {
98
return fn();
10-
} catch(e) {
9+
} catch (e) {
1110
let diff = performance.now() - startTime;
12-
if(diff > globals.interactorTimeout) {
11+
if (diff > globals.interactorTimeout) {
1312
throw e;
1413
} else {
15-
yield sleep(1);
14+
await sleep(1);
1615
}
1716
}
1817
}
1918
}
19+
20+
async function sleep(durationMS: number): Promise<void> {
21+
return new Promise((resolve) => setTimeout(resolve, durationMS));
22+
}

packages/core/src/interaction.ts

Lines changed: 20 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
/* eslint-disable @typescript-eslint/no-explicit-any */
2-
import { type Operation, type Task, run, Symbol } from '@effection/core';
3-
import { type InteractionOptions as SerializedInteractionOptions, globals, type InteractionType } from '@interactors/globals';
2+
import type { InteractionOptions as SerializedInteractionOptions, InteractionType } from '@interactors/globals';
43
import type { Interactor, FilterObject, FilterFn, FilterParams } from './specification.ts';
54
import { serializeInteractionOptions } from './serialize.ts';
65

@@ -25,7 +24,7 @@ export interface Interaction<E extends Element, T = void> extends Promise<T> {
2524
type: InteractionType;
2625

2726
interactor: Interactor<E, any>;
28-
run: (interactor: Interactor<E, any>) => Operation<T>;
27+
run: (interactor: Interactor<E, any>) => Promise<T>;
2928
/**
3029
* Return a description of the interaction
3130
*/
@@ -41,11 +40,9 @@ export interface Interaction<E extends Element, T = void> extends Promise<T> {
4140
/**
4241
* Perform the interaction
4342
*/
44-
action: () => Task<T>;
43+
action: () => Promise<T>;
4544

46-
check?: () => Task<T>;
47-
48-
halt: () => Promise<void>;
45+
check?: () => Promise<T>;
4946

5047
[interactionSymbol]: true;
5148
}
@@ -65,7 +62,7 @@ export interface AssertionInteraction<E extends Element, T = void> extends Inter
6562
/**
6663
* Perform the check
6764
*/
68-
check: () => Task<T>;
65+
check: () => Promise<T>;
6966
}
7067

7168
export type InteractionOptions<E extends Element, T> = {
@@ -74,70 +71,47 @@ export type InteractionOptions<E extends Element, T> = {
7471
filters?: FilterParams<any, any>;
7572
args: unknown[];
7673
interactor: Interactor<E, any>;
77-
run: (interactor: Interactor<E, any>) => Operation<T>;
74+
run: (interactor: Interactor<E, any>) => Promise<T>;
7875
}
7976

8077
export function createInteraction<E extends Element, T>(type: 'action', options: InteractionOptions<E, T>): ActionInteraction<E, T>
8178
export function createInteraction<E extends Element, T>(type: 'assertion', options: InteractionOptions<E, T>): AssertionInteraction<E, T>
8279
export function createInteraction<E extends Element, T, Q>(type: 'action', options: InteractionOptions<E, T>, apply: FilterFn<Q, Element>): ActionInteraction<E, T> & FilterObject<Q, Element>
8380
export function createInteraction<E extends Element, T, Q>(type: 'assertion', options: InteractionOptions<E, T>, apply: FilterFn<Q, Element>): AssertionInteraction<E, T> & FilterObject<Q, Element>
84-
export function createInteraction<E extends Element, T, Q>(type: InteractionType, options: InteractionOptions<E, T>, apply?: FilterFn<Q, Element>): Interaction<E, T> & Operation<T> {
85-
let task: Task<T>;
86-
let shouldCatchHalt = false
87-
88-
function operation(scope: Task): Operation<T> {
89-
let run = () => options.run(options.interactor);
90-
91-
return (globals.wrapInteraction
92-
? globals.wrapInteraction(() => scope.run(run), interaction)
93-
: globals.wrapAction(interaction.description, () => scope.run(run), type)) as Operation<T>;
94-
};
95-
96-
function action(): Task<T> {
97-
if(!task) {
98-
task = run(operation);
81+
export function createInteraction<E extends Element, T, Q>(type: InteractionType, options: InteractionOptions<E, T>, apply?: FilterFn<Q, Element>): Interaction<E, T> {
82+
let promise: Promise<T>;
83+
84+
let operation = () => options.run(options.interactor);
85+
86+
function action(): Promise<T> {
87+
if(!promise) {
88+
promise = operation();
9989
}
100-
return task;
90+
return promise;
10191
};
10292

103-
function catchHalt<T extends (reason: any) => any>(onReject?: T | null) {
104-
return (reason: any) => {
105-
if (shouldCatchHalt && reason instanceof Error && reason.message == 'halted') {
106-
return reason
107-
} else {
108-
onReject?.(reason)
109-
return reason
110-
}
111-
}
112-
}
113-
11493
let serializedOptions = serializeInteractionOptions(type, options)
115-
let interaction: Interaction<E, T> & Operation<T> = {
94+
let interaction: Interaction<E, T> = {
11695
type,
11796
options: serializedOptions,
11897
description: options.description,
11998
interactor: options.interactor,
12099
run: options.run,
121-
args: options.args,
100+
// args: options.args,
122101
action,
123102
check: type === 'assertion' ? action : undefined,
124103
code: () => serializedOptions.code(),
125-
halt: () => {
126-
shouldCatchHalt = true
127-
return action().halt()
128-
},
129104
[interactionSymbol]: true,
130105
[Symbol.toStringTag]: `[interaction ${options.description}]`,
131-
[Symbol.operation]: operation,
132106
then(onFulfill, onReject) {
133-
return action().then(onFulfill, catchHalt(onReject));
107+
return action().then(onFulfill, onReject);
134108
},
135109
catch(onReject) {
136-
return action().catch(catchHalt(onReject));
110+
return action().catch(onReject);
137111
},
138112
finally(handler) {
139113
return action().finally(handler);
140-
}
114+
},
141115
}
142116
if (apply) {
143117
return Object.assign(interaction, { apply });

packages/core/src/specification.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
2-
import type { Operation } from '@effection/core';
31
import type { FilterSet } from './filter-set.ts';
42
import type { Locator } from './locator.ts';
53
import type { ActionInteraction, AssertionInteraction, Interaction } from './interaction.ts';
@@ -128,7 +126,7 @@ export interface Interactor<E extends Element, F extends FilterParams<any, any>>
128126
apply: FilterFn<string, Element>;
129127
}
130128

131-
export type ActionFn<E extends Element, I extends Interactor<E, any>> = (interactor: I, ...args: any[]) => Operation<unknown>;
129+
export type ActionFn<E extends Element, I extends Interactor<E, any>> = (interactor: I, ...args: any[]) => Promise<unknown>;
132130

133131
export type FilterFn<T, E extends Element> = (element: E) => T;
134132

@@ -162,7 +160,7 @@ export type InteractorSpecification<E extends Element, F extends Filters<E>, A e
162160
}
163161

164162
export type ActionMethods<E extends Element, A extends Actions<E, I>, I extends Interactor<E, any>> = {
165-
[P in keyof A]: A[P] extends ((interactor: I, ...args: infer TArgs) => Operation<infer TReturn>)
163+
[P in keyof A]: A[P] extends ((interactor: I, ...args: infer TArgs) => Promise<infer TReturn>)
166164
? ((...args: TArgs) => ActionInteraction<E, TReturn>)
167165
: never;
168166
}

packages/core/test/fixtures.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ export const Datepicker = createInteractor<HTMLDivElement>("datepicker")
7171
month: Calendar().find(Header()).text(),
7272
})
7373
.actions({
74-
toggle: function* (interactor) {
75-
yield interactor.find(TextField({ placeholder: "YYYY-MM-DD" })).click();
74+
async toggle(interactor) {
75+
await interactor.find(TextField({ placeholder: "YYYY-MM-DD" })).click();
7676
},
7777
});
7878

0 commit comments

Comments
 (0)