From a596b2427932d484a5441d57232d8ab2434db864 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Van=20Keisbelck?= Date: Mon, 24 Apr 2023 14:21:44 +0200 Subject: [PATCH 01/15] CHANGELOG --- CHANGELOG.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d9c3f3c..9369af4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,27 @@ # Changelog +## v2.2.2 (24/04/2023) + +#### closed + +- [**closed**] DocSub async dispatch [#93](https://github.com/vankeisb/react-tea-cup/pull/93) +- [**closed**] Fix model undef check, update README [#88](https://github.com/vankeisb/react-tea-cup/pull/88) + +#### dependencies + +- [**dependencies**] Bump decode-uri-component from 0.2.0 to 0.2.2 [#89](https://github.com/vankeisb/react-tea-cup/pull/89) +- [**dependencies**] Bump qs from 6.5.2 to 6.5.3 [#90](https://github.com/vankeisb/react-tea-cup/pull/90) +- [**dependencies**] Bump express from 4.17.1 to 4.18.2 [#91](https://github.com/vankeisb/react-tea-cup/pull/91) +- [**dependencies**] Bump json5 from 1.0.1 to 1.0.2 [#92](https://github.com/vankeisb/react-tea-cup/pull/92) +- [**dependencies**] Bump async from 2.6.3 to 2.6.4 [#80](https://github.com/vankeisb/react-tea-cup/pull/80) +- [**dependencies**] Bump minimist from 1.2.5 to 1.2.6 [#79](https://github.com/vankeisb/react-tea-cup/pull/79) +- [**dependencies**] Bump cross-fetch from 2.2.3 to 2.2.6 [#81](https://github.com/vankeisb/react-tea-cup/pull/81) +- [**dependencies**] Bump eventsource from 1.0.7 to 1.1.1 [#82](https://github.com/vankeisb/react-tea-cup/pull/82) +- [**dependencies**] Bump jsdom from 16.4.0 to 16.5.0 [#84](https://github.com/vankeisb/react-tea-cup/pull/84) +- [**dependencies**] Bump terser from 4.8.0 to 4.8.1 [#85](https://github.com/vankeisb/react-tea-cup/pull/85) + +--- + ## v2.2.1 (02/09/2022) #### closed From 3c3111695eda27d343575197757d093f72147967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Van=20Keisbelck?= Date: Tue, 25 Apr 2023 15:47:37 +0200 Subject: [PATCH 02/15] bom lint --- .bomlint.json | 3 +++ package.json | 6 ++++-- yarn.lock | 3 +++ 3 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 .bomlint.json diff --git a/.bomlint.json b/.bomlint.json new file mode 100644 index 0000000..cc5c833 --- /dev/null +++ b/.bomlint.json @@ -0,0 +1,3 @@ +{ + "@types/react": "16.7.22" +} \ No newline at end of file diff --git a/package.json b/package.json index edcc7c5..1734105 100644 --- a/package.json +++ b/package.json @@ -12,10 +12,12 @@ "prettier": "2.0.5", "rimraf": "^2.6.3", "ts-jest": "24.0.2", - "typescript": "~3.9.7" + "typescript": "~3.9.7", + "bomlint": "file:/home/remi/projects/bomlint" }, "scripts": { "release:gh": "gren release", - "release:changelog": "gren changelog --tags all --generate --override" + "release:changelog": "gren changelog --tags all --generate --override", + "bomlint": "bomlint" } } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 11a8cd0..6b71a6c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2620,6 +2620,9 @@ body-parser@1.20.1: type-is "~1.6.18" unpipe "1.0.0" +"bomlint@file:../bomlint": + version "1.0.0" + bonjour@^3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5" From bc58a5db9cbcc5f611758f8e9f3d7c8d41ca5f41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Van=20Keisbelck?= Date: Wed, 26 Apr 2023 10:39:07 +0200 Subject: [PATCH 03/15] use bomlint to align deps --- .bomlint.json | 6 +++++- build.sh | 1 + package.json | 6 +++--- samples/package.json | 5 ++--- tea-cup/package.json | 2 +- yarn.lock | 34 ++++------------------------------ 6 files changed, 16 insertions(+), 38 deletions(-) diff --git a/.bomlint.json b/.bomlint.json index cc5c833..5d854d6 100644 --- a/.bomlint.json +++ b/.bomlint.json @@ -1,3 +1,7 @@ { - "@types/react": "16.7.22" + "@types/react": "^16.7.22", + "tea-cup-core": "2.2.2", + "react-tea-cup": "2.2.2", + "ts-jest": "^24.1.0", + "bomlint": "1.1.0" } \ No newline at end of file diff --git a/build.sh b/build.sh index eae3844..9cdf492 100755 --- a/build.sh +++ b/build.sh @@ -1,4 +1,5 @@ yarn install && \ +yarn bomlint && \ cd core && \ ./build.sh && \ cd ../tea-cup && \ diff --git a/package.json b/package.json index 1734105..1c7a2bb 100644 --- a/package.json +++ b/package.json @@ -11,13 +11,13 @@ "jest": "24.9.0", "prettier": "2.0.5", "rimraf": "^2.6.3", - "ts-jest": "24.0.2", + "ts-jest": "^24.1.0", "typescript": "~3.9.7", - "bomlint": "file:/home/remi/projects/bomlint" + "bomlint": "1.1.0" }, "scripts": { "release:gh": "gren release", "release:changelog": "gren changelog --tags all --generate --override", - "bomlint": "bomlint" + "bomlint": "bomlint package.json && bomlint ./core/package.json && bomlint ./tea-cup/package.json && bomlint ./samples/package.json" } } \ No newline at end of file diff --git a/samples/package.json b/samples/package.json index 686901e..e34dfa5 100644 --- a/samples/package.json +++ b/samples/package.json @@ -5,7 +5,7 @@ "proxy": "https://api.github.com", "dependencies": { "@types/node": "10.12.19", - "@types/react": "16.7.22", + "@types/react": "^16.7.22", "@types/react-dom": "16.0.11", "jest-enzyme": "^7.1.1", "react": "^16.7.0", @@ -36,7 +36,6 @@ "enzyme": "^3.10.0", "enzyme-adapter-react-16": "^1.15.1", "enzyme-to-json": "^3.4.2", - "jest-fetch-mock": "^2.1.2", - "ts-jest": "^24.1.0" + "jest-fetch-mock": "^2.1.2" } } \ No newline at end of file diff --git a/tea-cup/package.json b/tea-cup/package.json index a1d5f0d..944659a 100644 --- a/tea-cup/package.json +++ b/tea-cup/package.json @@ -23,7 +23,7 @@ "dependencies": {}, "peerDependencies": { "react": "^16.7.0 || ^17.0.1", - "tea-cup-core": "^2.2.2" + "tea-cup-core": "2.2.2" }, "devDependencies": { "@types/jsdom": "^16.2.5", diff --git a/yarn.lock b/yarn.lock index 6b71a6c..a39517b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1633,14 +1633,6 @@ "@types/prop-types" "*" csstype "^3.0.2" -"@types/react@16.7.22": - version "16.7.22" - resolved "https://registry.yarnpkg.com/@types/react/-/react-16.7.22.tgz#5bc6d166d5ac34b835756f0b736c7b1af0043e81" - integrity sha512-j/3tVoY09kHcTfbia4l67ofQn9xvktUvlC/4QN0KuBHAXlbU/wuGKMb8WfEb/vIcWxsOxHv559uYprkFDFfP8Q== - dependencies: - "@types/prop-types" "*" - csstype "^2.2.0" - "@types/stack-utils@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" @@ -2620,8 +2612,10 @@ body-parser@1.20.1: type-is "~1.6.18" unpipe "1.0.0" -"bomlint@file:../bomlint": - version "1.0.0" +bomlint@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/bomlint/-/bomlint-1.1.0.tgz#88ffa3d973beacfd55b5d2ca180bfeaad3254dd5" + integrity sha512-MWfvIQvI8RZJts7RKVJa8bEbGkrCt5oYC6/IYFM1aRUzY5ytpBzLv0bXtUwu8mL8o6AbMmFzx2oOkiBlV9gneQ== bonjour@^3.5.0: version "3.5.0" @@ -3909,11 +3903,6 @@ cssstyle@^2.3.0: dependencies: cssom "~0.3.6" -csstype@^2.2.0: - version "2.6.13" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.13.tgz#a6893015b90e84dd6e85d0e3b442a1e84f2dbe0f" - integrity sha512-ul26pfSQTZW8dcOnD2iiJssfXw0gdNVX9IJDH/X3K5DGPfj+fUYe3kB+swUY6BF3oZDxaID3AJt+9/ojSAE05A== - csstype@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.3.tgz#2b410bbeba38ba9633353aff34b05d9755d065f8" @@ -12359,21 +12348,6 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= -ts-jest@24.0.2: - version "24.0.2" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-24.0.2.tgz#8dde6cece97c31c03e80e474c749753ffd27194d" - integrity sha512-h6ZCZiA1EQgjczxq+uGLXQlNgeg02WWJBbeT8j6nyIBRQdglqbvzDoHahTEIiS6Eor6x8mK6PfZ7brQ9Q6tzHw== - dependencies: - bs-logger "0.x" - buffer-from "1.x" - fast-json-stable-stringify "2.x" - json5 "2.x" - make-error "1.x" - mkdirp "0.x" - resolve "1.x" - semver "^5.5" - yargs-parser "10.x" - ts-jest@^24.1.0: version "24.3.0" resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-24.3.0.tgz#b97814e3eab359ea840a1ac112deae68aa440869" From a87cfa33c5d62110c74f77b79604ac4d1aa52dc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Van=20Keisbelck?= Date: Thu, 27 Apr 2023 10:28:06 +0200 Subject: [PATCH 04/15] bump bomlint --- package.json | 4 ++-- yarn.lock | 15 +++++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 1c7a2bb..23a126d 100644 --- a/package.json +++ b/package.json @@ -13,11 +13,11 @@ "rimraf": "^2.6.3", "ts-jest": "^24.1.0", "typescript": "~3.9.7", - "bomlint": "1.1.0" + "bomlint": "1.2.0" }, "scripts": { "release:gh": "gren release", "release:changelog": "gren changelog --tags all --generate --override", - "bomlint": "bomlint package.json && bomlint ./core/package.json && bomlint ./tea-cup/package.json && bomlint ./samples/package.json" + "bomlint": "bomlint --allow-conflicts react package.json ./core/package.json ./tea-cup/package.json ./samples/package.json" } } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index a39517b..806cdd2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2612,10 +2612,12 @@ body-parser@1.20.1: type-is "~1.6.18" unpipe "1.0.0" -bomlint@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/bomlint/-/bomlint-1.1.0.tgz#88ffa3d973beacfd55b5d2ca180bfeaad3254dd5" - integrity sha512-MWfvIQvI8RZJts7RKVJa8bEbGkrCt5oYC6/IYFM1aRUzY5ytpBzLv0bXtUwu8mL8o6AbMmFzx2oOkiBlV9gneQ== +bomlint@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/bomlint/-/bomlint-1.2.0.tgz#d64deea823c5e0492bb92222c09169343248db12" + integrity sha512-2TE4FAl9YKSImhxMMBPG8s6itwZpWPpIUFfyJjKKODEo+juyARru5ze5fpJ78R3tls6CF0/cdxgk0P997P+LYA== + dependencies: + commander "^10.0.1" bonjour@^3.5.0: version "3.5.0" @@ -3354,6 +3356,11 @@ combined-stream@^1.0.6, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" +commander@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" + integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== + commander@^2.11.0, commander@^2.19.0, commander@^2.20.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" From cff3297fc27e63db8024ae830dd1c962fb3fb2f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Van=20Keisbelck?= Date: Thu, 27 Apr 2023 11:10:36 +0200 Subject: [PATCH 05/15] bomlint --- .bomlint.json | 2 +- package.json | 2 +- yarn.lock | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.bomlint.json b/.bomlint.json index 5d854d6..fb1f44d 100644 --- a/.bomlint.json +++ b/.bomlint.json @@ -3,5 +3,5 @@ "tea-cup-core": "2.2.2", "react-tea-cup": "2.2.2", "ts-jest": "^24.1.0", - "bomlint": "1.1.0" + "bomlint": "1.2.3" } \ No newline at end of file diff --git a/package.json b/package.json index 23a126d..f735955 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "rimraf": "^2.6.3", "ts-jest": "^24.1.0", "typescript": "~3.9.7", - "bomlint": "1.2.0" + "bomlint": "1.2.3" }, "scripts": { "release:gh": "gren release", diff --git a/yarn.lock b/yarn.lock index 806cdd2..32dc909 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2612,10 +2612,10 @@ body-parser@1.20.1: type-is "~1.6.18" unpipe "1.0.0" -bomlint@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/bomlint/-/bomlint-1.2.0.tgz#d64deea823c5e0492bb92222c09169343248db12" - integrity sha512-2TE4FAl9YKSImhxMMBPG8s6itwZpWPpIUFfyJjKKODEo+juyARru5ze5fpJ78R3tls6CF0/cdxgk0P997P+LYA== +bomlint@1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/bomlint/-/bomlint-1.2.3.tgz#f181ec55a2a5de6943b87af91ded237820d01ebd" + integrity sha512-RK+fDLoNKxH+TLjmCda7RwU8i7E5xTMAPqdzWVsNKqgg0siHgYSRBr0bnzppkTRGvXyUW/a2gbXzxSFWSbhVUg== dependencies: commander "^10.0.1" From 48107d3f13074aef90b39f2cd0753be9e5d86dcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Van=20Keisbelck?= Date: Thu, 27 Apr 2023 11:13:16 +0200 Subject: [PATCH 06/15] change node version in circle CI --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 4d27435..533ca72 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,7 +3,7 @@ version: 2 defaults: &defaults working_directory: ~/repo docker: - - image: circleci/node:erbium + - image: circleci/node:gallium jobs: build: From a9274aafffff6eee54411e94c2310819bbf7949e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Van=20Keisbelck?= Date: Wed, 3 May 2023 10:39:10 +0200 Subject: [PATCH 07/15] use Cmd for RAF --- core/src/TeaCup/Animation.ts | 44 ++++++++++++----------- samples/src/Samples/Raf.tsx | 68 ++++++++++++++++++++++++----------- tea-cup/src/TeaCup/Program.ts | 6 ++-- 3 files changed, 73 insertions(+), 45 deletions(-) diff --git a/core/src/TeaCup/Animation.ts b/core/src/TeaCup/Animation.ts index 5437341..eec8743 100644 --- a/core/src/TeaCup/Animation.ts +++ b/core/src/TeaCup/Animation.ts @@ -24,20 +24,8 @@ */ import { Sub } from './Sub'; - -let subs: Array> = []; - -let ticking = false; - -function tick() { - if (!ticking) { - ticking = true; - requestAnimationFrame((t: number) => { - subs.forEach((s) => s.trigger(t)); - ticking = false; - }); - } -} +import { Cmd } from './Cmd'; +import { Dispatcher } from './Dispatcher'; class RafSub extends Sub { readonly mapper: (t: number) => M; @@ -49,13 +37,9 @@ class RafSub extends Sub { protected onInit() { super.onInit(); - subs.push(this); - tick(); - } - - protected onRelease() { - super.onRelease(); - subs = subs.filter((s) => s !== this); + setTimeout(() => { + requestAnimationFrame((t) => this.trigger(t)); + }); } trigger(t: number) { @@ -63,6 +47,24 @@ class RafSub extends Sub { } } +/** + * @deprecated Use {@link rafCmd} and manage + * @param mapper + */ export function onAnimationFrame(mapper: (t: number) => M): Sub { return new RafSub(mapper); } + +class RafCmd extends Cmd { + constructor(private readonly mapper: (t: number) => Msg) { + super(); + } + + execute(dispatch: Dispatcher): void { + requestAnimationFrame((t) => dispatch(this.mapper(t))); + } +} + +export function rafCmd(mapper: (t: number) => Msg): Cmd { + return new RafCmd(mapper); +} diff --git a/samples/src/Samples/Raf.tsx b/samples/src/Samples/Raf.tsx index b6c2ebf..9300239 100644 --- a/samples/src/Samples/Raf.tsx +++ b/samples/src/Samples/Raf.tsx @@ -23,22 +23,28 @@ * */ -import { Dispatcher, Cmd, noCmd, Sub, onAnimationFrame } from 'tea-cup-core'; +import { Cmd, Dispatcher, noCmd, rafCmd, Sub } from 'tea-cup-core'; import * as React from 'react'; export interface Model { readonly started: boolean; readonly t: number; + readonly t2: number; readonly fps: number; readonly animText: string; } -export type Msg = { type: 'raf'; t: number } | { type: 'toggle' } | { type: 'text-changed'; text: string }; +export type Msg = + | { type: 'raf'; t: number } + | { type: 'toggle' } + | { type: 'text-changed'; text: string } + | { type: 'raf2'; t: number }; export function init() { return noCmd({ started: false, t: 0, + t2: 0, fps: 0, animText: 'This text gets animated...', }); @@ -65,6 +71,9 @@ export function view(dispatch: Dispatcher, model: Model) { /> Time = {Math.round(model.t)} +
+ t2 = {Math.round(model.t2)} +
{fps} {anim} @@ -101,18 +110,43 @@ function viewAnim(text: String, t: number) { export function update(msg: Msg, model: Model): [Model, Cmd] { switch (msg.type) { case 'toggle': - return noCmd({ ...model, started: !model.started }); - case 'raf': - const delta = msg.t - model.t; - const fps = delta === 0 - ? model.fps - : 1000 / delta; - return noCmd({ + const newModel: Model = { ...model, - t: msg.t, - fps: fps, - }); + started: !model.started, + }; + return [ + newModel, + newModel.started + ? Cmd.batch([ + rafCmd((t: number) => ({ type: 'raf', t } as Msg)), + rafCmd((t: number) => ({ type: 'raf2', t } as Msg)), + ]) + : Cmd.none(), + ]; + case 'raf': { + const delta = msg.t - model.t; + const fps = delta === 0 ? model.fps : 1000 / delta; + const cmd: Cmd = model.started ? rafCmd((t: number) => ({ type: 'raf', t } as Msg)) : Cmd.none(); + return [ + { + ...model, + t: msg.t, + fps: fps, + }, + cmd, + ]; + } + case 'raf2': { + const cmd: Cmd = model.started ? rafCmd((t: number) => ({ type: 'raf2', t } as Msg)) : Cmd.none(); + return [ + { + ...model, + t2: msg.t, + }, + cmd, + ]; + } case 'text-changed': return noCmd({ ...model, @@ -121,12 +155,6 @@ export function update(msg: Msg, model: Model): [Model, Cmd] { } } -export function subscriptions(model: Model) { - if (model.started) { - return onAnimationFrame((t: number) => { - return { type: 'raf', t: t } as Msg; - }); - } else { - return Sub.none(); - } +export function subscriptions(model: Model): Sub { + return Sub.none(); } diff --git a/tea-cup/src/TeaCup/Program.ts b/tea-cup/src/TeaCup/Program.ts index 38f73e5..9341cb0 100644 --- a/tea-cup/src/TeaCup/Program.ts +++ b/tea-cup/src/TeaCup/Program.ts @@ -91,10 +91,8 @@ export class Program extends Component, nev const d = this.dispatch.bind(this); - setTimeout(() => { - newSub.init(d); - prevSub?.release(); - }); + newSub.init(d); + prevSub?.release(); // perform commands in a separate timout, to // make sure that this dispatch is done From 89dfba135ee353665ea37478f72ff54f75e95cdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Van=20Keisbelck?= Date: Wed, 3 May 2023 11:29:14 +0200 Subject: [PATCH 08/15] Do not clear dispatcher in Subs, use isActive() instead Fix RAF (no Cmds) Fix Doc events (timeout) --- core/src/TeaCup/Animation.ts | 22 +---- core/src/TeaCup/Sub.ts | 10 +- samples/src/Samples/EventsSample.tsx | 132 +++++++++++++------------- samples/src/Samples/Raf.tsx | 55 +++++------ tea-cup/src/TeaCup/DocumentEvents.ts | 136 ++++++++++++++++----------- tea-cup/src/TeaCup/Testing.tsx | 9 +- 6 files changed, 183 insertions(+), 181 deletions(-) diff --git a/core/src/TeaCup/Animation.ts b/core/src/TeaCup/Animation.ts index eec8743..129abdd 100644 --- a/core/src/TeaCup/Animation.ts +++ b/core/src/TeaCup/Animation.ts @@ -24,8 +24,6 @@ */ import { Sub } from './Sub'; -import { Cmd } from './Cmd'; -import { Dispatcher } from './Dispatcher'; class RafSub extends Sub { readonly mapper: (t: number) => M; @@ -38,7 +36,7 @@ class RafSub extends Sub { protected onInit() { super.onInit(); setTimeout(() => { - requestAnimationFrame((t) => this.trigger(t)); + this.isActive() && requestAnimationFrame((t) => this.trigger(t)); }); } @@ -47,24 +45,6 @@ class RafSub extends Sub { } } -/** - * @deprecated Use {@link rafCmd} and manage - * @param mapper - */ export function onAnimationFrame(mapper: (t: number) => M): Sub { return new RafSub(mapper); } - -class RafCmd extends Cmd { - constructor(private readonly mapper: (t: number) => Msg) { - super(); - } - - execute(dispatch: Dispatcher): void { - requestAnimationFrame((t) => dispatch(this.mapper(t))); - } -} - -export function rafCmd(mapper: (t: number) => Msg): Cmd { - return new RafCmd(mapper); -} diff --git a/core/src/TeaCup/Sub.ts b/core/src/TeaCup/Sub.ts index 663d11e..88e9922 100644 --- a/core/src/TeaCup/Sub.ts +++ b/core/src/TeaCup/Sub.ts @@ -27,6 +27,7 @@ import { Dispatcher } from './Dispatcher'; export abstract class Sub { protected dispatcher: Dispatcher | undefined; + private active: boolean = false; static none(): Sub { return new SubNone(); @@ -38,16 +39,21 @@ export abstract class Sub { init(dispatch: Dispatcher): void { this.dispatcher = dispatch; + this.active = true; this.onInit(); } release(): void { - this.dispatcher = undefined; + this.active = false; this.onRelease(); } + isActive() { + return this.active; + } + protected dispatch(m: Msg): void { - this.dispatcher && this.dispatcher(m); + this.dispatcher?.(m); } protected onInit() {} diff --git a/samples/src/Samples/EventsSample.tsx b/samples/src/Samples/EventsSample.tsx index 8de1622..290479a 100644 --- a/samples/src/Samples/EventsSample.tsx +++ b/samples/src/Samples/EventsSample.tsx @@ -25,37 +25,41 @@ import * as React from 'react'; import { Dispatcher, Cmd, Sub, noCmd, nothing, just, Maybe } from 'tea-cup-core'; -import {DocumentEvents, WindowEvents} from "react-tea-cup"; +import { DocumentEvents, WindowEvents } from 'react-tea-cup'; export type Model = { - clicked: Maybe - moved: Maybe - scrolled: Maybe - nbResizeLeft: number - nbResizeRight: number + clicked: Maybe; + moved: Maybe; + scrolled: Maybe; + nbResizeLeft: number; + nbResizeRight: number; }; type MousePosition = { pos: Position; page: Position; offset: Position; -} +}; -type Position = [number, number] +type Position = [number, number]; -export type Msg = { - type: 'clicked', - position: MousePosition -} | { - type: 'moved', - position: MousePosition -} | { - type: 'resized', - left: boolean -} | { - type: 'scrolled', - scroll: Position -}; +export type Msg = + | { + type: 'clicked'; + position: MousePosition; + } + | { + type: 'moved'; + position: MousePosition; + } + | { + type: 'resized'; + left: boolean; + } + | { + type: 'scrolled'; + scroll: Position; + }; export function init(): [Model, Cmd] { return noCmd({ @@ -70,18 +74,9 @@ export function init(): [Model, Cmd] { export function view(dispatch: Dispatcher, model: Model) { return (
- {model.clicked - .map(viewMousePosition('Clicked')) - .withDefault(
Waiting for click ...
) - } - {model.moved - .map(viewMousePosition('Moved')) - .withDefault(
Waiting for move ...
) - } - {model.scrolled - .map(viewPosition('Scrolled')) - .withDefault(
Waiting for move ...
) - } + {model.clicked.map(viewMousePosition('Clicked')).withDefault(
Waiting for click ...
)} + {model.moved.map(viewMousePosition('Moved')).withDefault(
Waiting for move ...
)} + {model.scrolled.map(viewPosition('Scrolled')).withDefault(
Waiting for move ...
)}
resized left : {model.nbResizeLeft}
resized right : {model.nbResizeRight}
@@ -93,21 +88,21 @@ export function update(msg: Msg, model: Model): [Model, Cmd] { case 'clicked': { const model1: Model = { ...model, - clicked: just(msg.position) + clicked: just(msg.position), }; return [model1, Cmd.none()]; } case 'moved': { const model1: Model = { ...model, - moved: just(msg.position) + moved: just(msg.position), }; return [model1, Cmd.none()]; } case 'scrolled': { const model1: Model = { ...model, - scrolled: just(msg.scroll) + scrolled: just(msg.scroll), }; return [model1, Cmd.none()]; } @@ -126,40 +121,46 @@ const windowEvents = new WindowEvents(); export function subscriptions(model: Model): Sub { return Sub.batch([ - documentEvents.on('click', (e: MouseEvent) => ( - { - type: 'clicked', - position: { - pos: [e.x, e.y], - page: [e.pageX, e.pageY], - offset: [e.offsetX, e.offsetY] - } - } as Msg - )), - documentEvents.on('mousemove', (e: MouseEvent) => ({ - type: 'moved', - position: { - pos: [e.x, e.y], - page: [e.pageX, e.pageY], - offset: [e.offsetX, e.offsetY] - } - } as Msg)), + documentEvents.on( + 'click', + (e: MouseEvent) => + ({ + type: 'clicked', + position: { + pos: [e.x, e.y], + page: [e.pageX, e.pageY], + offset: [e.offsetX, e.offsetY], + }, + } as Msg), + ), + documentEvents.on( + 'mousemove', + (e: MouseEvent) => + ({ + type: 'moved', + position: { + pos: [e.x, e.y], + page: [e.pageX, e.pageY], + offset: [e.offsetX, e.offsetY], + }, + } as Msg), + ), windowEvents.on('scroll', (e: Event) => { return { type: 'scrolled', - scroll: [window.scrollX, window.scrollY] + scroll: [window.scrollX, window.scrollY], } as Msg; }), windowEvents.on('resize', () => { return { type: 'resized', - left: true + left: true, } as Msg; }), windowEvents.on('resize', () => { return { type: 'resized', - left: false + left: false, } as Msg; }), ]); @@ -167,14 +168,15 @@ export function subscriptions(model: Model): Sub { function viewMousePosition(title: string) { return (position: MousePosition) => { - return (
- {title}: - {viewPosition('Position')(position.pos)}  - {viewPosition('Page')(position.page)}  - {viewPosition('Offset')(position.offset)} -
+ return ( +
+ {title}: + {viewPosition('Position')(position.pos)}  + {viewPosition('Page')(position.page)}  + {viewPosition('Offset')(position.offset)} +
); - } + }; } function viewPosition(title: string) { @@ -184,5 +186,5 @@ function viewPosition(title: string) { {title} {position[0]},{position[1]}  ); - } + }; } diff --git a/samples/src/Samples/Raf.tsx b/samples/src/Samples/Raf.tsx index 9300239..1acb4fb 100644 --- a/samples/src/Samples/Raf.tsx +++ b/samples/src/Samples/Raf.tsx @@ -23,7 +23,7 @@ * */ -import { Cmd, Dispatcher, noCmd, rafCmd, Sub } from 'tea-cup-core'; +import { Cmd, Dispatcher, noCmd, onAnimationFrame, Sub } from 'tea-cup-core'; import * as React from 'react'; export interface Model { @@ -110,42 +110,22 @@ function viewAnim(text: String, t: number) { export function update(msg: Msg, model: Model): [Model, Cmd] { switch (msg.type) { case 'toggle': - const newModel: Model = { - ...model, - started: !model.started, - }; - return [ - newModel, - newModel.started - ? Cmd.batch([ - rafCmd((t: number) => ({ type: 'raf', t } as Msg)), - rafCmd((t: number) => ({ type: 'raf2', t } as Msg)), - ]) - : Cmd.none(), - ]; + return noCmd({ ...model, started: !model.started }); case 'raf': { const delta = msg.t - model.t; const fps = delta === 0 ? model.fps : 1000 / delta; - const cmd: Cmd = model.started ? rafCmd((t: number) => ({ type: 'raf', t } as Msg)) : Cmd.none(); - return [ - { - ...model, - t: msg.t, - fps: fps, - }, - cmd, - ]; + return noCmd({ + ...model, + t: msg.t, + fps: fps, + }); } case 'raf2': { - const cmd: Cmd = model.started ? rafCmd((t: number) => ({ type: 'raf2', t } as Msg)) : Cmd.none(); - return [ - { - ...model, - t2: msg.t, - }, - cmd, - ]; + return noCmd({ + ...model, + t2: msg.t, + }); } case 'text-changed': return noCmd({ @@ -156,5 +136,16 @@ export function update(msg: Msg, model: Model): [Model, Cmd] { } export function subscriptions(model: Model): Sub { - return Sub.none(); + if (model.started) { + return Sub.batch([ + onAnimationFrame((t: number) => { + return { type: 'raf', t: t } as Msg; + }), + onAnimationFrame((t: number) => { + return { type: 'raf2', t: t } as Msg; + }), + ]); + } else { + return Sub.none(); + } } diff --git a/tea-cup/src/TeaCup/DocumentEvents.ts b/tea-cup/src/TeaCup/DocumentEvents.ts index 61d23e0..03e3076 100644 --- a/tea-cup/src/TeaCup/DocumentEvents.ts +++ b/tea-cup/src/TeaCup/DocumentEvents.ts @@ -23,89 +23,111 @@ * */ -import {Sub} from 'tea-cup-core'; +import { Sub } from 'tea-cup-core'; type Listener = (ev: E) => any; type ListenerOptions = boolean | AddEventListenerOptions; type Mapper = (ev: E) => Msg; +let subCount = 0; + class DocSub extends Sub { - private readonly listener: Listener; + private readonly listener: Listener; + private sc: number; - constructor( - private readonly documentEvents: EventMapEvents, - private readonly key: K, - private readonly mapper: Mapper, - private readonly options?: ListenerOptions - ) { - super(); - this.listener = (e) => this.dispatch(this.mapper(e)); - } + constructor( + private readonly documentEvents: EventMapEvents, + private readonly key: K, + private readonly mapper: Mapper, + private readonly options?: ListenerOptions, + ) { + super(); + subCount++; + this.sc = subCount; + this.listener = (e) => + this.isActive() && + setTimeout(() => { + this.dispatch(this.mapper(e)); + }); + } - protected onInit() { - super.onInit(); - this.documentEvents.doAddListener(this.key, this.listener, this.options) - } + protected onInit() { + super.onInit(); + this.documentEvents.doAddListener(this.key, this.listener, this.options); + } - protected onRelease() { - super.onRelease(); - this.documentEvents.doRemoveListener(this.key, this.listener, this.options) - } + protected onRelease() { + super.onRelease(); + this.documentEvents.doRemoveListener(this.key, this.listener, this.options); + } } abstract class EventMapEvents { + abstract doAddListener( + key: K, + listener: (ev: Map[K]) => any, + options?: boolean | AddEventListenerOptions, + ): void; - abstract doAddListener(key: K, - listener: (ev: Map[K]) => any, - options?: boolean | AddEventListenerOptions): void; - - abstract doRemoveListener(key: K, - listener: (ev: Map[K]) => any, - options?: boolean | AddEventListenerOptions): void; + abstract doRemoveListener( + key: K, + listener: (ev: Map[K]) => any, + options?: boolean | AddEventListenerOptions, + ): void; - /** - * Subscribe to an event. - * @param key the event type to subscribe to. - * @param mapper map the event to a message. - * @param options options for this listener - */ - public on(key: K, - mapper: (e: Map[K]) => Msg, - options?: boolean | AddEventListenerOptions): Sub { - return new DocSub(this, key, mapper, options); - } + /** + * Subscribe to an event. + * @param key the event type to subscribe to. + * @param mapper map the event to a message. + * @param options options for this listener + */ + public on( + key: K, + mapper: (e: Map[K]) => Msg, + options?: boolean | AddEventListenerOptions, + ): Sub { + return new DocSub(this, key, mapper, options); + } } /** * Subscribe to document events. */ export class DocumentEvents extends EventMapEvents { - doAddListener(key: K, - listener: (ev: DocumentEventMap[K]) => any, - options?: boolean | AddEventListenerOptions): void { - document.addEventListener(key, listener, options); - } + doAddListener( + key: K, + listener: (ev: DocumentEventMap[K]) => any, + options?: boolean | AddEventListenerOptions, + ): void { + document.addEventListener(key, listener, options); + } - doRemoveListener(key: K, - listener: (ev: DocumentEventMap[K]) => any, - options?: boolean | AddEventListenerOptions): void { - document.removeEventListener(key, listener, options); - } + doRemoveListener( + key: K, + listener: (ev: DocumentEventMap[K]) => any, + options?: boolean | AddEventListenerOptions, + ): void { + document.removeEventListener(key, listener, options); + } } /** * Bonus, WindowEvents */ export class WindowEvents extends EventMapEvents { - doAddListener(key: K, - listener: (ev: WindowEventMap[K]) => any, - options?: boolean | AddEventListenerOptions): void { - window.addEventListener(key, listener, options); - } + doAddListener( + key: K, + listener: (ev: WindowEventMap[K]) => any, + options?: boolean | AddEventListenerOptions, + ): void { + window.addEventListener(key, listener, options); + } - doRemoveListener(key: K, - listener: (ev: WindowEventMap[K]) => any, - options?: boolean | AddEventListenerOptions): void { - window.removeEventListener(key, listener, options); - } + doRemoveListener( + key: K, + listener: (ev: WindowEventMap[K]) => any, + options?: boolean | AddEventListenerOptions, + ): void { + window.removeEventListener(key, listener, options); + } } diff --git a/tea-cup/src/TeaCup/Testing.tsx b/tea-cup/src/TeaCup/Testing.tsx index e7c9515..899a1fc 100644 --- a/tea-cup/src/TeaCup/Testing.tsx +++ b/tea-cup/src/TeaCup/Testing.tsx @@ -172,10 +172,11 @@ class TestableSub extends Sub { protected onInit(): void { setTimeout(() => { - if (this.dispatcher !== undefined) { - const d = this.dispatcher.bind(this); - this.cmds.map((cmd) => cmd.execute(d)); - } + this.isActive() && this.cmds.forEach((cmd) => cmd.execute((m) => this.dispatch(m))); + // if (this.dispatcher !== undefined) { + // const d = this.dispatcher.bind(this); + // this.cmds.map((cmd) => cmd.execute(d)); + // } }, 0); } } From 311ad1ab1f0cae2fe325a70726cf9f4edc8a6221 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Van=20Keisbelck?= Date: Wed, 3 May 2023 13:08:22 +0200 Subject: [PATCH 09/15] webtests --- samples/src/App.tsx | 132 ++++++++-------- samples/src/Samples/Counter.tsx | 12 +- samples/src/Samples/EventsSample.tsx | 22 ++- samples/src/Samples/PortsSample.tsx | 1 - samples/src/Samples/Raf.tsx | 13 +- webtests/.gitignore | 1 + webtests/pom.xml | 145 ++++++++++++++++++ .../test/java/react/tea/cup/SamplesTest.java | 92 +++++++++++ 8 files changed, 333 insertions(+), 85 deletions(-) create mode 100755 webtests/.gitignore create mode 100644 webtests/pom.xml create mode 100644 webtests/src/test/java/react/tea/cup/SamplesTest.java diff --git a/samples/src/App.tsx b/samples/src/App.tsx index 07227bd..3297dd5 100755 --- a/samples/src/App.tsx +++ b/samples/src/App.tsx @@ -24,18 +24,7 @@ */ import React from 'react'; -import { - Cmd, - Dispatcher, - just, - map, - Maybe, - maybeOf, - noCmd, - nothing, - Sub, - Task, -} from 'tea-cup-core'; +import { Cmd, Dispatcher, just, map, Maybe, maybeOf, noCmd, nothing, Sub, Task } from 'tea-cup-core'; import { DevTools, newUrl, @@ -60,7 +49,7 @@ import * as TimeSample from './Samples/TimeSample'; import * as EventsSample from './Samples/EventsSample'; import * as SelectSample from './Samples/SelectSample'; import * as PortsSample from './Samples/PortsSample'; -import { appSamplePorts } from "./Samples/PortsSample"; +import { appSamplePorts } from './Samples/PortsSample'; enum Tab { All, @@ -367,7 +356,7 @@ function mapPortsSample(m: PortsSample.Msg): Msg { return { type: 'portsSample', child: m, - } + }; } function view(dispatch: Dispatcher, model: Model) { @@ -464,16 +453,16 @@ function viewTodos(dispatch: Dispatcher, todoMvc: TodoMvc) { {active ? ( {label} ) : ( - { - e.preventDefault(); - dispatch({ type: 'tabClicked', tab: t }); - }} - > - {label} - - )} + { + e.preventDefault(); + dispatch({ type: 'tabClicked', tab: t }); + }} + > + {label} + + )} ); } @@ -485,46 +474,46 @@ function viewTodos(dispatch: Dispatcher, todoMvc: TodoMvc) { {todos.length === 0 ? (

You have nothing to do ! Neat !!

) : ( -
-
    - {viewTab(Tab.All)} - {viewTab(Tab.Open)} - {viewTab(Tab.Closed)} -
- -
- )} +
+
    + {viewTab(Tab.All)} + {viewTab(Tab.Open)} + {viewTab(Tab.Closed)} +
+ +
+ )} ); } @@ -566,7 +555,6 @@ function viewSamples(dispatch: Dispatcher, samples: Samples) { return (
{backToHome(dispatch)} -

Samples

This is the samples app for react-tea-cup.

@@ -594,10 +582,14 @@ function viewSamples(dispatch: Dispatcher, samples: Samples) { {SelectSample.view(map(dispatch, mapSelectSample), samples.select)}

Ports

{PortsSample.view(map(dispatch, mapPortsSample), samples.ports)} - +
); } @@ -661,7 +653,7 @@ function update(msg: Msg, model: Model): [Model, Cmd] { const macTime = TimeSample.update(msg.child, s.time); return [{ ...s, time: macTime[0] }, macTime[1].map(mapTimeSample)]; }); - case "portsSample": + case 'portsSample': return mapSample((s: Samples) => { const mac = PortsSample.update(msg.child, s.ports); return [{ ...s, ports: mac[0] }, mac[1].map(mapPortsSample)]; diff --git a/samples/src/Samples/Counter.tsx b/samples/src/Samples/Counter.tsx index 8480c1a..d4bae77 100644 --- a/samples/src/Samples/Counter.tsx +++ b/samples/src/Samples/Counter.tsx @@ -42,10 +42,14 @@ export function init(): [Model, Cmd] { // need this "dispatch" arg, so that you can emit Msgs export function view(dispatch: Dispatcher, model: Model) { return ( -
- - {model} - +
+ + {model} +
); } diff --git a/samples/src/Samples/EventsSample.tsx b/samples/src/Samples/EventsSample.tsx index 290479a..305d520 100644 --- a/samples/src/Samples/EventsSample.tsx +++ b/samples/src/Samples/EventsSample.tsx @@ -73,13 +73,19 @@ export function init(): [Model, Cmd] { export function view(dispatch: Dispatcher, model: Model) { return ( -
- {model.clicked.map(viewMousePosition('Clicked')).withDefault(
Waiting for click ...
)} + + {model.clicked + .map(viewMousePosition('Clicked')) + .withDefault(
Waiting for click ...
)} {model.moved.map(viewMousePosition('Moved')).withDefault(
Waiting for move ...
)} {model.scrolled.map(viewPosition('Scrolled')).withDefault(
Waiting for move ...
)} -
resized left : {model.nbResizeLeft}
-
resized right : {model.nbResizeRight}
-
+
+ resized left : {model.nbResizeLeft} +
+
+ resized right : {model.nbResizeRight} +
+ ); } @@ -169,8 +175,10 @@ export function subscriptions(model: Model): Sub { function viewMousePosition(title: string) { return (position: MousePosition) => { return ( -
- {title}: +
+ + {title}:{' '} + {viewPosition('Position')(position.pos)}  {viewPosition('Page')(position.page)}  {viewPosition('Offset')(position.offset)} diff --git a/samples/src/Samples/PortsSample.tsx b/samples/src/Samples/PortsSample.tsx index 379ea0f..2f534d2 100644 --- a/samples/src/Samples/PortsSample.tsx +++ b/samples/src/Samples/PortsSample.tsx @@ -53,7 +53,6 @@ export function init(): [Model, Cmd] { export function view(dispatch: Dispatcher, model: Model) { return (
-

Counter with ports

Value = {model}
diff --git a/samples/src/Samples/Raf.tsx b/samples/src/Samples/Raf.tsx index 1acb4fb..25e1701 100644 --- a/samples/src/Samples/Raf.tsx +++ b/samples/src/Samples/Raf.tsx @@ -60,6 +60,7 @@ export function view(dispatch: Dispatcher, model: Model) {
@@ -70,11 +71,17 @@ export function view(dispatch: Dispatcher, model: Model) { } />
- Time = {Math.round(model.t)} + + Time = {Math.round(model.t)} +
- t2 = {Math.round(model.t2)} + + t2 = {Math.round(model.t2)} +
- + {fps} {anim}
diff --git a/webtests/.gitignore b/webtests/.gitignore new file mode 100755 index 0000000..1de5659 --- /dev/null +++ b/webtests/.gitignore @@ -0,0 +1 @@ +target \ No newline at end of file diff --git a/webtests/pom.xml b/webtests/pom.xml new file mode 100644 index 0000000..236f584 --- /dev/null +++ b/webtests/pom.xml @@ -0,0 +1,145 @@ + + 4.0.0 + + react-tea-cup + webtests + LATEST-SNAPSHOT + war + webtests + + + 11 + 11 + ${project.basedir}/../samples/build + 8080 + + false + + true + true + + + + + com.pojosontheweb + selenium-utils-core + 2.0.1 + + + junit + junit + 4.13.2 + + + com.pojosontheweb + monte-repack + 1.1 + + + + + ${project.artifactId} + + + + + + + + org.apache.maven.plugins + maven-war-plugin + 3.3.2 + + false + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.2 + + true + + + + org.apache.maven.plugins + maven-failsafe-plugin + 3.0.0 + + + + integration-test + verify + + + + + + ${failsafeArgLine} + + chrome + ${webtests.headless} + ${webtests.window.position} + ${webtests.findr.verbose} + ${webtests.video.enabled} + ${project.build.directory}/videos + http://localhost:${backend.port} + + + Europe/Paris + + true + + + + org.eclipse.jetty + jetty-maven-plugin + 9.4.51.v20230217 + + + ${backend.port} + + + /dummy + + ^$ + + + + + / + ${frontend.react.sandbox.directory} + + + 13 + 9966 + stop-jetty + 10 + + -Xdebug -agentlib:jdwp=transport=dt_socket,address=9999,server=y,suspend=n + + + + start-jetty + pre-integration-test + + start + + + 0 + + + + stop-jetty + post-integration-test + + stop + + + + + + + diff --git a/webtests/src/test/java/react/tea/cup/SamplesTest.java b/webtests/src/test/java/react/tea/cup/SamplesTest.java new file mode 100644 index 0000000..cd65858 --- /dev/null +++ b/webtests/src/test/java/react/tea/cup/SamplesTest.java @@ -0,0 +1,92 @@ +package react.tea.cup; + +import com.pojosontheweb.selenium.Findr; +import com.pojosontheweb.selenium.ManagedDriverJunit4TestBase; +import org.junit.Test; +import org.openqa.selenium.Dimension; +import org.openqa.selenium.WebElement; + +import java.util.function.Consumer; + +import static com.pojosontheweb.selenium.Findrs.textEquals; +import static org.junit.Assert.assertEquals; + +public class SamplesTest extends ManagedDriverJunit4TestBase { + + private String baseUrl = System.getProperty("webtests.base.url", "http://localhost:3000"); + + @Test + public void testCounter() { + getWebDriver().get(baseUrl + "/samples"); + + Consumer assertCounter = i -> $("#counter-value").where(textEquals(Integer.toString(i))).eval(); + Findr buttonSub = $("#counter-sub"); + Findr buttonAdd = $("#counter-add"); + + assertCounter.accept(0); + + + buttonAdd.click(); + assertCounter.accept(1); + buttonAdd.click(); + buttonAdd.click(); + assertCounter.accept(3); + buttonSub.click(); + assertCounter.accept(2); + } + + @Test + public void testRaf() { + getWebDriver().get(baseUrl + "/samples#sample-raf"); + + Findr button = $("#raf-start"); + Findr time1 = $("#raf-time-1"); + Findr time2 = $("#raf-time-2"); + + time1.where(textEquals("0")).eval(); + time2.where(textEquals("0")).eval(); + button.click(); + + // sleep to let RAF do its magic for some time... + try { + Thread.sleep(1000); + }catch (Exception e) { + } + + button.click(); + String t1 = time1.eval(WebElement::getText); + String t2 = time2.eval(WebElement::getText); + assertEquals(t1, t2); + } + + @Test + public void testEvents() { + getWebDriver().get(baseUrl + "/samples#sample-events"); + + Findr waitForClick = $$(".wait-for-click").expectOne(); + waitForClick.eval(); + waitForClick.click(); + + $$(".view-mouse-pos .vmp-title") + .where(textEquals("Clicked")) + .expectOne() + .eval(); + + Findr resizedLeft = $("#resized-left"); + Findr resizedRight = $("#resized-right"); + + Consumer assertResizes = i -> { + resizedLeft.where(textEquals(Integer.toString(i))).eval(); + resizedRight.where(textEquals(Integer.toString(i))).eval(); + }; + + assertResizes.accept(1); + + Dimension d = getWebDriver().manage().window().getSize(); + Dimension d2 = new Dimension(d.width, d.height + 1); + getWebDriver().manage().window().setSize(d2); + + assertResizes.accept(2); + } + +} From 4f0d19d4d36b4aa3d85354dccb5b74505c6bfa5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Van=20Keisbelck?= Date: Wed, 3 May 2023 13:32:57 +0200 Subject: [PATCH 10/15] webtests --- .../cup/{SamplesTest.java => SamplesIT.java} | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) rename webtests/src/test/java/react/tea/cup/{SamplesTest.java => SamplesIT.java} (90%) diff --git a/webtests/src/test/java/react/tea/cup/SamplesTest.java b/webtests/src/test/java/react/tea/cup/SamplesIT.java similarity index 90% rename from webtests/src/test/java/react/tea/cup/SamplesTest.java rename to webtests/src/test/java/react/tea/cup/SamplesIT.java index cd65858..47584b7 100644 --- a/webtests/src/test/java/react/tea/cup/SamplesTest.java +++ b/webtests/src/test/java/react/tea/cup/SamplesIT.java @@ -2,6 +2,7 @@ import com.pojosontheweb.selenium.Findr; import com.pojosontheweb.selenium.ManagedDriverJunit4TestBase; +import org.junit.Before; import org.junit.Test; import org.openqa.selenium.Dimension; import org.openqa.selenium.WebElement; @@ -11,21 +12,23 @@ import static com.pojosontheweb.selenium.Findrs.textEquals; import static org.junit.Assert.assertEquals; -public class SamplesTest extends ManagedDriverJunit4TestBase { +public class SamplesIT extends ManagedDriverJunit4TestBase { private String baseUrl = System.getProperty("webtests.base.url", "http://localhost:3000"); + @Before + public void navigateToSamples() { + getWebDriver().get(baseUrl); + $$("a").where(textEquals("samples")).expectOne().click(); + } + @Test public void testCounter() { - getWebDriver().get(baseUrl + "/samples"); - Consumer assertCounter = i -> $("#counter-value").where(textEquals(Integer.toString(i))).eval(); Findr buttonSub = $("#counter-sub"); Findr buttonAdd = $("#counter-add"); assertCounter.accept(0); - - buttonAdd.click(); assertCounter.accept(1); buttonAdd.click(); @@ -37,6 +40,7 @@ public void testCounter() { @Test public void testRaf() { + getWebDriver().get(baseUrl + "/samples#sample-raf"); Findr button = $("#raf-start"); @@ -80,13 +84,13 @@ public void testEvents() { resizedRight.where(textEquals(Integer.toString(i))).eval(); }; - assertResizes.accept(1); + assertResizes.accept(0); Dimension d = getWebDriver().manage().window().getSize(); Dimension d2 = new Dimension(d.width, d.height + 1); getWebDriver().manage().window().setSize(d2); - assertResizes.accept(2); + assertResizes.accept(1); } } From 78b84048e1f338a189f8e7106b32a136bb6918c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Van=20Keisbelck?= Date: Wed, 3 May 2023 13:46:10 +0200 Subject: [PATCH 11/15] circle ci --- .circleci/config.yml | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 533ca72..0c5f588 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,4 +1,6 @@ -version: 2 +version: 2.1 +orbs: + browser-tools: circleci/browser-tools@1.1.1 defaults: &defaults working_directory: ~/repo @@ -16,6 +18,31 @@ jobs: root: ~/repo paths: . + webtests: + working_directory: ~/repo + docker: + - image: circleci/openjdk:8-jdk-browsers + environment: + DISPLAY: :99 + + steps: + - run: sudo Xvfb :99 -screen 0 1920x1200x24 > /dev/null 2>&1 & + - attach_workspace: + at: ~/repo + - browser-tools/install-chrome + - browser-tools/install-chromedriver + - run: + command: | + google-chrome --version + chromedriver --version + ps -efa | grep Xvfb + name: Check install + - run: cd webtests && export DISPLAY=:99 && mvn clean install -Dwebdriver.chrome.driver=/usr/local/bin/chromedriver + - store_artifacts: + path: ~/repo/webtests/target/surefire-reports + - store_artifacts: + path: ~/repo/webtests/target/videos + deploy: <<: *defaults steps: @@ -34,9 +61,13 @@ workflows: filters: tags: only: /\d+\.\d+\.\d+/ + - webtests: + requires: + - build - deploy: requires: - build + - webtests filters: tags: only: /\d+\.\d+\.\d+/ From 56b9873bb8ca1eff0a03ddb830ff963fbb94fc17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Van=20Keisbelck?= Date: Wed, 3 May 2023 13:59:21 +0200 Subject: [PATCH 12/15] fix snapshots --- .../__snapshots__/Counter.test.ts.snap | 7 ++++++- .../__snapshots__/ParentChild.test.ts.snap | 21 ++++++++++++++++--- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/samples/src/Samples/__snapshots__/Counter.test.ts.snap b/samples/src/Samples/__snapshots__/Counter.test.ts.snap index 7d900f9..6ade472 100644 --- a/samples/src/Samples/__snapshots__/Counter.test.ts.snap +++ b/samples/src/Samples/__snapshots__/Counter.test.ts.snap @@ -3,16 +3,21 @@ exports[`Test Counter view state snapshot 1`] = `
- + 1313 - + 0 - + 0 - + 0