From 778de6adaf78478f284eff2a2cf3646d9a8aefd1 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Mon, 19 May 2025 09:08:43 +0200 Subject: [PATCH] :sparkles: Add minimal testing structure --- common/src/app/common/files/builder.cljc | 17 +++--- library/package.json | 10 ++- library/playground/sample1.js | 2 +- library/src/lib/builder.cljs | 9 ++- library/test/builder.test.js | 77 ++++++++++++++++++++++++ 5 files changed, 100 insertions(+), 15 deletions(-) create mode 100644 library/test/builder.test.js diff --git a/common/src/app/common/files/builder.cljc b/common/src/app/common/files/builder.cljc index c51dccde9a..210051262b 100644 --- a/common/src/app/common/files/builder.cljc +++ b/common/src/app/common/files/builder.cljc @@ -125,7 +125,8 @@ [:path {:optional true} ::sm/text]]) (def ^:private check-add-component - (sm/check-fn schema:add-component)) + (sm/check-fn schema:add-component + :hint "invalid arguments passed for add-component")) (def decode-add-component (sm/decode-fn schema:add-component sm/json-transformer)) @@ -136,7 +137,8 @@ [:file-id {:optional true} ::sm/uuid]]) (def ^:private check-add-component-instance - (sm/check-fn schema:add-component-instance)) + (sm/check-fn schema:add-component-instance + :hint "invalid arguments passed for add-component-instance")) (def decode-add-component-instance (sm/decode-fn schema:add-component-instance sm/json-transformer)) @@ -196,7 +198,8 @@ [state params] (let [params (-> params (assoc :features cfeat/default-features) - (assoc :migrations fmig/available-migrations)) + (assoc :migrations fmig/available-migrations) + (update :id default-uuid)) file (types.file/make-file params :create-page false)] (-> state (update ::files assoc (:id file) file) @@ -390,7 +393,8 @@ (defn add-component [state params] (let [{:keys [component-id file-id name path]} - (check-add-component params) + (-> (check-add-component params) + (update :component-id default-uuid)) frame-id (get state ::current-frame-id) @@ -398,9 +402,6 @@ page-id (get state ::current-page-id) - component-id - (or component-id (uuid/next)) - change1 (d/without-nils {:type :add-component @@ -485,7 +486,7 @@ [state guide] (let [guide (cond-> guide (nil? (:id guide)) - (assoc :id (uuid/next))) + (update :id default-uuid)) page-id (::current-page-id state)] (-> state (commit-change diff --git a/library/package.json b/library/package.json index f4664da6d1..0ee94c5a86 100644 --- a/library/package.json +++ b/library/package.json @@ -13,15 +13,19 @@ "resolutions": { "@zip.js/zip.js@npm:^2.7.44": "patch:@zip.js/zip.js@npm%3A2.7.60#~/.yarn/patches/@zip.js-zip.js-npm-2.7.60-b6b814410b.patch" }, + "imports": { + "#self": { + "default": "./target/library/penpot.js" + } + }, "scripts": { "clear:shadow-cache": "rm -rf .shadow-cljs", "build": "yarn run clear:shadow-cache && clojure -M:dev:shadow-cljs release library", "fmt:clj": "cljfmt fix --parallel=true src/ test/", "fmt:clj:check": "cljfmt check --parallel=false src/ test/", "lint:clj": "clj-kondo --parallel --lint src/", - "build:test": "clojure -M:dev:shadow-cljs compile test", - "test": "yarn run build:test && node target/tests/test.js", - "watch:test": "mkdir -p target/tests && concurrently \"clojure -M:dev:shadow-cljs watch test\" \"nodemon -C -d 2 -w target/tests --exec 'node target/tests/test.js'\"", + "test": "node --test", + "watch:test": "node --test --watch", "watch": "yarn run clear:shadow-cache && clojure -M:dev:shadow-cljs watch library" }, "devDependencies": { diff --git a/library/playground/sample1.js b/library/playground/sample1.js index db8b51016f..0f90bb32e7 100644 --- a/library/playground/sample1.js +++ b/library/playground/sample1.js @@ -1,4 +1,4 @@ -import * as penpot from "../target/library/penpot.js"; +import * as penpot from "#self"; import { writeFile, readFile } from 'fs/promises'; import { createWriteStream } from 'fs'; import { Writable } from "stream"; diff --git a/library/src/lib/builder.cljs b/library/src/lib/builder.cljs index 4cd19dd639..df9b909cb3 100644 --- a/library/src/lib/builder.cljs +++ b/library/src/lib/builder.cljs @@ -35,7 +35,7 @@ :enumerable true :this false :get (fn [] cause)} - {:name "data" + {:name "explain" :enumerable true :this false :get (fn [] @@ -68,7 +68,7 @@ (defn- create-builder-api [state] - (obj/reify {:name "File"} + (obj/reify {:name "BuildContext"} :currentFileId {:get #(dm/str (get @state ::fb/current-file-id))} @@ -275,8 +275,11 @@ :genId (fn [] - (dm/str (uuid/next))))) + (dm/str (uuid/next))) + :getInternalState + (fn [] + (json/->js @state)))) (defn create-build-context "Create an empty builder state context." diff --git a/library/test/builder.test.js b/library/test/builder.test.js new file mode 100644 index 0000000000..de94f5c3a0 --- /dev/null +++ b/library/test/builder.test.js @@ -0,0 +1,77 @@ +import assert from "node:assert/strict"; +import test from "node:test"; + +import * as penpot from "#self"; + +test("create empty context", () => { + const context = penpot.createBuildContext(); + assert.ok(context); +}); + +test("create context with single file", () => { + const context = penpot.createBuildContext(); + context.addFile({name: "sample"}); + + const internalState = context.getInternalState(); + + // console.log(internalState); + + assert.ok(internalState.files); + assert.equal(typeof internalState.files, "object"); + assert.equal(typeof internalState.currentFileId, "string"); + + const file = internalState.files[internalState.currentFileId]; + assert.ok(file); +}); + +test("create context with two file", () => { + const context = penpot.createBuildContext(); + + const fileId_1 = context.addFile({name: "sample 1"}); + const fileId_2 = context.addFile({name: "sample 2"}); + + const internalState = context.getInternalState(); + + // console.log(internalState.files[fileId_1]) + + assert.ok(internalState.files[fileId_1]); + assert.ok(internalState.files[fileId_2]); + assert.equal(internalState.files[fileId_1].name, "sample 1"); + assert.equal(internalState.files[fileId_2].name, "sample 2"); + + const file = internalState.files[fileId_2]; + + assert.ok(file.data); + assert.ok(file.data.pages); + assert.ok(file.data.pagesIndex); + assert.equal(file.data.pages.length, 0) +}); + +test("create context with file and page", () => { + const context = penpot.createBuildContext(); + + const fileId = context.addFile({name: "file 1"}); + const pageId = context.addPage({name: "page 1"}); + + const internalState = context.getInternalState(); + + const file = internalState.files[fileId]; + + assert.ok(file, "file should exist"); + + assert.ok(file.data); + assert.ok(file.data.pages); + + assert.equal(file.data.pages.length, 1); + + const page = file.data.pagesIndex[pageId]; + + assert.ok(page, "page should exist"); + assert.ok(page.objects, "page objects should exist"); + assert.equal(page.id, pageId); + + + const rootShape = page.objects["00000000-0000-0000-0000-000000000000"]; + assert.ok(rootShape, "root shape should exist"); + assert.equal(rootShape.id, "00000000-0000-0000-0000-000000000000"); +});