@lernapps/app-templates 0.1.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,7 +7,7 @@ with which a creator and their AI assistant build a learning app.
7
7
  ## Who it is for
8
8
 
9
9
  - **Creators and their assistants** never open this repo: the generator of
10
- [lernapps/tooling](https://github.com/lernapps/tooling) copies a template folder into a new app. Start at
10
+ [lernapps/tooling](https://github.com/lernapps/tooling) writes a template's scaffold into a new app. Start at
11
11
  [lernapps.net/apps/eintragen/](https://lernapps.net/apps/eintragen/), or, as an assistant, at
12
12
  [lernapps.net/tooling/llms.txt](https://lernapps.net/tooling/llms.txt).
13
13
  - **Maintainers of an archetype** change its template and its runtime here.
@@ -24,7 +24,7 @@ feature: assistants read it before they choose an archetype.
24
24
  | [`explainer/`](explainer/) | an explainer: chapters of pages with sections, formulas, figures, tables, timelines, definitions with a glossary, quotes, code and YouTube videos behind two clicks, and an exercise on every page (the quiz's question types, and `generated` exercises drawn from a seed and property-tested at build), readable without JavaScript, in one or more languages; an optional self-assessment of the app or a chapter, checked as a whole; Vue components for what no block can express | the content as YAML in `src/`: `app.yaml`, a folder per chapter with `chapter.yaml` and its pages, `data/` and `images/`, and `components/` ([schema](runtime/explainer/explainer.v1.schema.json)) |
25
25
  | [`interactive/`](interactive/) | an interactive app whose doing is the content (a game, a trainer): a static start page, readable without JavaScript, and an app page with the app's own Vue components, its routes as `app/#<id>`; the build plays its playthroughs against its core | `src/app.yaml` ([schema](runtime/interactive/interactive.v1.schema.json)), the core `src/core/index.ts` (`start(seed, route)`, `step(state, input)` with a key or an action of its root component, optional `tick(state, dt)`), its components in `src/ui/`, data in `src/data/`, and `src/playthroughs/*.yaml` ([schema](runtime/interactive/playthrough.v1.schema.json)) |
26
26
 
27
- - [`runtime/`](runtime/): the runtime of each archetype, published to npm as `@lernapps/app-templates` (with the template folders, which `lernapps create` of `@lernapps/tooling` copies out of the installed package); its exports
27
+ - [`runtime/`](runtime/): the runtime of each archetype, published to npm as `@lernapps/app-templates` (with the template folders, complete example apps, and the scaffold of each archetype: `lernapps create` of `@lernapps/tooling` copies the paths `lernapps.scaffold.<archetype>` in [`package.json`](package.json) lists and the placeholder in [`scaffold/<archetype>/`](scaffold/), and leaves the example in the installed package; [`scripts/scaffold.ts`](scripts/scaffold.ts) writes the same for the CI job `scaffold`); its exports
28
28
  are in [`package.json`](package.json), what each does in the comments of its source. The quiz's questions also work
29
29
  one by one, for other archetypes that embed them as exercises: `@lernapps/app-templates/quiz/question` (schema,
30
30
  validation, rendering, checker, messages; a question's texts may be maps by language), `startQuestion` of `@lernapps/app-templates/quiz` and the helpers of
@@ -805,13 +805,32 @@ async function expectResultLine(request, copied, here, first, id, n) {
805
805
  expect(response.status(), `${address} answers`).toBe(200);
806
806
  expect(await response.text(), "the tutor page has the exercise").toContain(id);
807
807
  }
808
- /** The explainer's tests, for the content in `root`/src. */
808
+ /**
809
+ * The tests of an explainer's content, for the content in `root`/src: what every app runs (e2e/explainer.e2e.ts).
810
+ * Without JavaScript every page as its content says, previous and next, the app's own components and the checks of
811
+ * its exercise components. What the runtime does the same in every app is explainerRuntimeTests.
812
+ */
809
813
  function explainerTests(root = ".") {
814
+ explainerSuite(root, "content");
815
+ }
816
+ /**
817
+ * The tests of the explainer's runtime on the content in `root`/src: the exercises of each type, the videos, the tutor
818
+ * ways, the start page, the self-assessments, what is stored. The template folder and the fixtures of
819
+ * lernapps/app-templates run them (e2e/runtime.e2e.ts); an app does not, its scaffold has no such file: they test the
820
+ * runtime, which is the same in every app, not the app's content.
821
+ */
822
+ function explainerRuntimeTests(root = ".") {
823
+ explainerSuite(root, "runtime");
824
+ }
825
+ /** Only at desktop width, in a test of what does not depend on the width; what a page shows is tested at 360 px too. */
826
+ const desktopOnly = (page) => test.skip((page.viewportSize()?.width ?? 0) <= 400, "only at desktop width");
827
+ function explainerSuite(root, part) {
810
828
  const app = outline(root);
829
+ const content = part === "content";
811
830
  test.describe("explainer", () => {
812
831
  test.describe.configure({ mode: "parallel" });
813
832
  test.use({ reducedMotion: "reduce" });
814
- test.describe("without JavaScript", () => {
833
+ if (content) test.describe("without JavaScript", () => {
815
834
  test.use({ javaScriptEnabled: false });
816
835
  for (const lang of app.languages) {
817
836
  for (const item of app.pages[lang] ?? []) test(`${item.url || "./"}: headings, sections, formulas, figures and anchors as in the content`, async ({ page }) => {
@@ -848,6 +867,7 @@ function explainerTests(root = ".") {
848
867
  if (item.kind === "start") await expect(page.locator(".explainer-tutor-about h2")).toHaveText(message(item.lang, "tutorTitle"));
849
868
  });
850
869
  test(`${lang}: previous and next form one chain over all pages`, async ({ page }) => {
870
+ desktopOnly(page);
851
871
  const order = (app.pages[lang] ?? []).map((item) => item.url);
852
872
  const first = order[0];
853
873
  if (first === void 0) throw new Error(`no page in ${lang}`);
@@ -881,7 +901,7 @@ function explainerTests(root = ".") {
881
901
  });
882
902
  test.describe("with JavaScript", () => {
883
903
  test.skip(({ viewport }) => (viewport?.width ?? 0) > 400, "the exercises run at 360 px");
884
- for (const item of app.pages["de"] ?? []) {
904
+ if (!content) for (const item of app.pages["de"] ?? []) {
885
905
  const types = /* @__PURE__ */ new Map();
886
906
  for (const exercise of item.exercises) if (!types.has(exercise.type)) types.set(exercise.type, exercise);
887
907
  if (types.size === 0) continue;
@@ -895,13 +915,13 @@ function explainerTests(root = ".") {
895
915
  expect(kept.length, "an answer per open task").toBe(types.has("open-task") ? 1 : 0);
896
916
  });
897
917
  }
898
- for (const item of app.pages["de"] ?? []) {
918
+ if (!content) for (const item of app.pages["de"] ?? []) {
899
919
  if (item.videos.length === 0) continue;
900
920
  test(`${item.url}: the videos load nothing before a click, the player after it, directly once chosen`, async ({ page, baseURL }) => {
901
921
  await checkVideos(page, item, new URL(baseURL ?? page.url()).origin);
902
922
  });
903
923
  }
904
- for (const item of app.pages["de"] ?? []) {
924
+ if (content) for (const item of app.pages["de"] ?? []) {
905
925
  if (item.components.length === 0) continue;
906
926
  test(`${item.url}: each component hydrates without a console error (${item.components.map((component) => component.name).join(", ")})`, async ({ page }) => {
907
927
  await checkComponents(page, item);
@@ -909,6 +929,7 @@ function explainerTests(root = ".") {
909
929
  });
910
930
  }
911
931
  });
932
+ if (content) return;
912
933
  for (const item of (app.pages["de"] ?? []).filter((candidate) => candidate.exercises.some((exercise) => exercise.kind === "generated"))) test(`${item.url}: the address holds the task of each exercise, and the tutor button gives them to the prompt`, async ({ page }) => {
913
934
  await page.addInitScript(() => {
914
935
  const copied = [];
@@ -1308,4 +1329,4 @@ function explainerTests(root = ".") {
1308
1329
  });
1309
1330
  });
1310
1331
  }
1311
- export { explainerTests };
1332
+ export { explainerRuntimeTests, explainerTests };
package/dist/quiz-e2e.mjs CHANGED
@@ -8,14 +8,53 @@ import { readFileSync } from "node:fs";
8
8
  const de = QUIZ_MESSAGES.de;
9
9
  /** The quiz's own texts in `lang`. */
10
10
  const messagesOf = messagesIn;
11
- /** The quiz's tests, for the question bank in `bank` (relative to the app's root). */
11
+ /**
12
+ * The tests of a quiz's content, for the question bank in `bank` (relative to the app's root): what every app runs
13
+ * (e2e/quiz.e2e.ts). Each question's link opens it with what it shows; without JavaScript every question and its
14
+ * solution can be read; each other language has its page. What the runtime does the same in every app is
15
+ * quizRuntimeTests.
16
+ */
12
17
  function quizTests(bank = "src/quiz.json") {
18
+ quizSuite(bank, "content");
19
+ }
20
+ /**
21
+ * The tests of the quiz's runtime on the question bank in `bank`: the right answer counts and a wrong one does not, with
22
+ * the feedback in view; the seed and the order; a run through every question to the full score; how many questions
23
+ * the learner chooses; what is stored. The template folder and the fixtures of lernapps/app-templates run them
24
+ * (e2e/runtime.e2e.ts); an app does not, its scaffold has no such file: they test the runtime, which is the same in
25
+ * every app, and their time grows with the bank (lernapps/app-templates#125).
26
+ */
27
+ function quizRuntimeTests(bank = "src/quiz.json") {
28
+ quizSuite(bank, "runtime");
29
+ }
30
+ function quizSuite(bank, part) {
31
+ const content = part === "content";
13
32
  const all = JSON.parse(readFileSync(bank, "utf8"));
14
33
  const languages = quizLanguages(all);
15
34
  const quiz = quizIn(all, "de");
16
35
  test.describe("quiz", () => {
17
36
  test.use({ reducedMotion: "reduce" });
18
- for (const item of quiz.questions) {
37
+ if (content) {
38
+ for (const item of quiz.questions) test(`${item.id} (${item.type}): its link opens it, with what it shows`, async ({ page }) => {
39
+ await page.goto(`./#${questionId(item)}`);
40
+ await expect(question(page, item)).toBeVisible();
41
+ await expect(page.locator(".question:visible")).toHaveCount(1);
42
+ await expect(question(page, item).locator("legend")).toHaveText(item.text);
43
+ if (item.material !== void 0) await expectMaterial(page, item);
44
+ });
45
+ test.describe("without JavaScript", () => {
46
+ test.use({ javaScriptEnabled: false });
47
+ test("every question and its solution can be read", async ({ page }) => {
48
+ await page.goto("./");
49
+ for (const item of quiz.questions) {
50
+ await expect(question(page, item).locator("legend")).toHaveText(item.text);
51
+ await expectMaterial(page, item, { loaded: false });
52
+ await expectBackground(page.locator(`#loesung-${item.id}`), item);
53
+ }
54
+ });
55
+ });
56
+ }
57
+ if (!content) for (const item of quiz.questions) {
19
58
  test(`${item.id} (${item.type}): its link opens it and the right answer counts`, async ({ page }) => {
20
59
  await page.goto(`./#${questionId(item)}`);
21
60
  await expect(question(page, item)).toBeVisible();
@@ -34,10 +73,6 @@ function quizTests(bank = "src/quiz.json") {
34
73
  await expect(reveal.locator(".question-badge-right").first()).toHaveText(de.rightOption);
35
74
  } else await expect(reveal).toContainText(de.rightAnswer);
36
75
  });
37
- if (item.material !== void 0) test(`${item.id} (${item.type}): what it shows is there, and its images load`, async ({ page }) => {
38
- await page.goto(`./#${questionId(item)}`);
39
- await expectMaterial(page, item);
40
- });
41
76
  test(`${item.id} (${item.type}): a wrong answer does not count`, async ({ page }) => {
42
77
  await page.goto(`./#${questionId(item)}`);
43
78
  await answerQuestion(page, item, wrongAnswer(item));
@@ -47,7 +82,7 @@ function quizTests(bank = "src/quiz.json") {
47
82
  if (item.type === "single-choice" || item.type === "multiple-choice") await expect(question(page, item).locator(".question-badge-chosen").first()).toHaveText(de.yourChoice);
48
83
  });
49
84
  }
50
- test("the seed in the address gives the order; without one, the address gets one", async ({ page }) => {
85
+ if (!content) test("the seed in the address gives the order; without one, the address gets one", async ({ page }) => {
51
86
  const everything = `&n=${quiz.questions.length}`;
52
87
  const order = async (address) => {
53
88
  await page.goto(address);
@@ -69,7 +104,7 @@ function quizTests(bank = "src/quiz.json") {
69
104
  await page.goto("./");
70
105
  await expect.poll(() => new URL(page.url()).searchParams.get("seed")).toMatch(/^\d+$/);
71
106
  });
72
- test("all right answers give the full score, then the solutions show", async ({ page }) => {
107
+ if (!content) test("all right answers give the full score, then the solutions show", async ({ page }) => {
73
108
  await page.goto("./");
74
109
  if (quiz.questions.length > 1) await page.locator(".quiz-start button").click();
75
110
  expect(await page.evaluate(() => Object.keys(localStorage))).toEqual([]);
@@ -89,7 +124,7 @@ function quizTests(bank = "src/quiz.json") {
89
124
  expect(stored[0]).toMatch(/^lernapps:.+:last-result$/);
90
125
  } else expect(stored).toEqual([]);
91
126
  });
92
- if (quiz.questions.length > 1) test("the learner chooses how many questions to answer; the address keeps the choice", async ({ page }) => {
127
+ if (!content && quiz.questions.length > 1) test("the learner chooses how many questions to answer; the address keeps the choice", async ({ page }) => {
93
128
  await page.goto("./?seed=11");
94
129
  await expect(page.locator(".quiz-start")).toBeVisible();
95
130
  await expect(page.locator(".question:visible")).toHaveCount(0);
@@ -113,23 +148,12 @@ function quizTests(bank = "src/quiz.json") {
113
148
  await expect(page.locator(".question")).toHaveCount(1);
114
149
  await expect(page.locator(".question")).toHaveAttribute("data-id", item.id);
115
150
  });
116
- test.describe("without JavaScript", () => {
117
- test.use({ javaScriptEnabled: false });
118
- test("every question and its solution can be read", async ({ page }) => {
119
- await page.goto("./");
120
- for (const item of quiz.questions) {
121
- await expect(question(page, item).locator("legend")).toHaveText(item.text);
122
- await expectMaterial(page, item, { loaded: false });
123
- await expectBackground(page.locator(`#loesung-${item.id}`), item);
124
- }
125
- });
126
- });
127
151
  for (const lang of languages.slice(1)) {
128
152
  const local = quizIn(all, lang);
129
153
  const words = messagesOf(lang);
130
154
  const address = `./${lang}/`;
131
155
  test.describe(`in ${lang}`, () => {
132
- test.describe("without JavaScript", () => {
156
+ if (content) test.describe("without JavaScript", () => {
133
157
  test.use({ javaScriptEnabled: false });
134
158
  test(`the page is in ${lang}, every question and its solution can be read, the switch leads to every language`, async ({ page }) => {
135
159
  await page.goto(address);
@@ -151,14 +175,14 @@ function quizTests(bank = "src/quiz.json") {
151
175
  }
152
176
  });
153
177
  });
154
- test(`what a question shows, in ${lang}`, async ({ page }) => {
178
+ if (content) test(`what a question shows, in ${lang}`, async ({ page }) => {
155
179
  const item = local.questions.find((candidate) => candidate.material !== void 0);
156
180
  test.skip(item === void 0, "no question shows content");
157
181
  if (item === void 0) return;
158
182
  await page.goto(`${address}#${questionId(item)}`);
159
183
  await expectMaterial(page, item);
160
184
  });
161
- test(`one question, answered in ${lang}`, async ({ page }) => {
185
+ if (!content) test(`one question, answered in ${lang}`, async ({ page }) => {
162
186
  const item = local.questions[0];
163
187
  if (item === void 0) throw new Error("the quiz has no questions");
164
188
  await page.goto(`${address}#${questionId(item)}`);
@@ -171,4 +195,4 @@ function quizTests(bank = "src/quiz.json") {
171
195
  }
172
196
  });
173
197
  }
174
- export { answerQuestion, expectBackground, expectFeedbackInView, expectMaterial, quizTests };
198
+ export { answerQuestion, expectBackground, expectFeedbackInView, expectMaterial, quizRuntimeTests, quizTests };
@@ -228,6 +228,30 @@ addresses: qg-understandable
228
228
  :::
229
229
  ```
230
230
 
231
+ ## A New App Gets the Scaffold, Not the Example
232
+
233
+ `lernapps create` copies only the scaffold of the archetype into a new app: the paths that `lernapps.scaffold.<archetype>`
234
+ in this package's `package.json` lists (the entry, the configuration, the e2e entry) and a placeholder as start content
235
+ (`scaffold/<archetype>/`: one question, one page with one exercise, or a counter as the core). The template folder
236
+ stays a complete example app, which this repo checks; an app does not copy it, the creator's assistant looks it up in
237
+ `node_modules/@lernapps/app-templates/<archetype>/`. A copied example shaped the new app too much: its structure,
238
+ its topic and its tone stayed long after the plan said otherwise. The list is data in this package, which alone knows
239
+ what is configuration and what is example; the tooling only reads it. The CI job `scaffold` checks the scaffold as an
240
+ app, so that a new app passes `lernapps check` from its first commit. `lernapps update` never writes the scaffold
241
+ again: it moves libraries, not content. Rejected: a function `scaffold()` exported by the package, which would need the
242
+ built package even in a clone given to `create --templates`; start content inside the template folder, which the
243
+ template's own checks would read as part of the example.
244
+
245
+ ```arc42
246
+ :::decision
247
+ id: dec-scaffold
248
+ title: A new app gets the scaffold and a placeholder, not the example app
249
+ status: accepted
250
+ date: 2026-11-02
251
+ addresses: qg-understandable
252
+ :::
253
+ ```
254
+
231
255
  ## Tutor Variant
232
256
 
233
257
  The optional tutor is a handoff to the learner's own assistant: after a click, a prompt (copied or passed to a chosen
@@ -488,8 +488,12 @@ path: runtime/explainer/assessment.ts
488
488
 
489
489
  ### End-to-end tests
490
490
 
491
- Built. `explainerTests()` derives from the content what every page must show, checks it without JavaScript in every
492
- language, and with JavaScript one exercise per type and page and every component.
491
+ Built, in two parts. `explainerTests()` checks the app's content: it derives from the content what every page must
492
+ show and checks it without JavaScript in every language, previous and next, and with JavaScript the app's own
493
+ components and the checks of its exercise components. `explainerRuntimeTests()` checks the runtime, the same in every
494
+ app: one exercise per type and page, the videos, the tutor ways, the start page, the self-assessments, what is stored.
495
+ Only this repo runs the second part, on the template and its fixtures (`explainer/e2e/runtime.e2e.ts`, not in the
496
+ scaffold).
493
497
 
494
498
  ```arc42
495
499
  :::building-block
@@ -504,7 +508,7 @@ requires: if-archetype-content, if-runtime-texts, if-questions
504
508
 
505
509
  #### Tests interface
506
510
 
507
- The app's `e2e/explainer.e2e.ts` only calls `explainerTests()`.
511
+ The app's `e2e/explainer.e2e.ts`, part of the scaffold, only calls `explainerTests()`.
508
512
 
509
513
  ```arc42
510
514
  :::interface
@@ -0,0 +1,6 @@
1
+ import { explainerRuntimeTests } from "@lernapps/app-templates/explainer/e2e";
2
+
3
+ // The tests of the explainer runtime, which this repo runs on the template and its fixtures. Not part of the scaffold
4
+ // (lernapps.scaffold in the package.json of @lernapps/app-templates): a new app runs only explainerTests(), on its
5
+ // content.
6
+ explainerRuntimeTests();
@@ -9,10 +9,11 @@
9
9
  },
10
10
  "devDependencies": {
11
11
  "@lernapps/app-templates": "file:..",
12
- "@lernapps/tooling": "^0.1.2",
12
+ "@lernapps/tooling": "0.1.3",
13
13
  "vite-plus": "1.4.0"
14
14
  },
15
15
  "overrides": {
16
+ "@lernapps/app-templates": "file:..",
16
17
  "vite": "npm:@voidzero-dev/vite-plus-core@1.4.0"
17
18
  }
18
19
  }
@@ -9,10 +9,11 @@
9
9
  },
10
10
  "devDependencies": {
11
11
  "@lernapps/app-templates": "file:..",
12
- "@lernapps/tooling": "^0.1.2",
12
+ "@lernapps/tooling": "0.1.3",
13
13
  "vite-plus": "1.4.0"
14
14
  },
15
15
  "overrides": {
16
+ "@lernapps/app-templates": "file:..",
16
17
  "vite": "npm:@voidzero-dev/vite-plus-core@1.4.0"
17
18
  }
18
19
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lernapps/app-templates",
3
- "version": "0.1.1",
3
+ "version": "0.2.1",
4
4
  "description": "The templates of the archetypes of lernapps.net apps, and the runtime of each archetype that apps depend on (the quiz: engine, build step, styles, end-to-end tests, the schema of the question bank, the questions it shares with the explainer are in ./questions; the explainer: build step, client module with its exercises, the islands of its Vue components, styles, end-to-end tests, the schema of its content; the interactive archetype: build step, the start page and the app page around the app's own Vue components and core, its playthroughs, styles, end-to-end tests, the schemas of its start page and its playthroughs)",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -14,6 +14,7 @@
14
14
  "explainer",
15
15
  "interactive",
16
16
  "quiz",
17
+ "scaffold",
17
18
  "!**/package-lock.json",
18
19
  "!**/node_modules"
19
20
  ],
@@ -142,6 +143,40 @@
142
143
  "explainer",
143
144
  "interactive",
144
145
  "quiz"
145
- ]
146
+ ],
147
+ "scaffold": {
148
+ "explainer": [
149
+ ".gitignore",
150
+ "index.html",
151
+ "package.json",
152
+ "tsconfig.json",
153
+ "vite.config.ts",
154
+ "playwright.config.ts",
155
+ "src/main.ts",
156
+ "e2e/explainer.e2e.ts"
157
+ ],
158
+ "interactive": [
159
+ ".arc42ignore",
160
+ ".gitignore",
161
+ "index.html",
162
+ "package.json",
163
+ "tsconfig.json",
164
+ "vite.config.ts",
165
+ "playwright.config.ts",
166
+ "src/main.ts",
167
+ "src/env.d.ts",
168
+ "e2e/interactive.e2e.ts"
169
+ ],
170
+ "quiz": [
171
+ ".gitignore",
172
+ "index.html",
173
+ "package.json",
174
+ "tsconfig.json",
175
+ "vite.config.ts",
176
+ "playwright.config.ts",
177
+ "src/main.ts",
178
+ "e2e/quiz.e2e.ts"
179
+ ]
180
+ }
146
181
  }
147
182
  }
@@ -196,8 +196,12 @@ path: runtime/quiz/engine.ts
196
196
 
197
197
  ### End-to-end tests
198
198
 
199
- Built. `quizTests()` checks every question of the bank in the browser (deep link, right and wrong answer, feedback in
200
- view with the focus), the full score, the page without JavaScript, and each further language.
199
+ Built, in two parts. `quizTests()` checks the app's content: each question's deep link with what it shows, the page
200
+ without JavaScript with every question and its solution, and each further language. `quizRuntimeTests()` checks the
201
+ runtime, the same in every app: right and wrong answer with the feedback in view and the focus, the seed and the order,
202
+ the run to the full score, the number of questions, what is stored. Only this repo runs the second part, on the
203
+ template and its fixtures (`quiz/e2e/runtime.e2e.ts`, not in the scaffold): its time grows with the bank, and it tests
204
+ nothing an app writes.
201
205
 
202
206
  ```arc42
203
207
  :::building-block
@@ -212,7 +216,7 @@ requires: if-archetype-content, if-runtime-texts
212
216
 
213
217
  #### Tests interface
214
218
 
215
- The app's `e2e/quiz.e2e.ts` only calls `quizTests()`.
219
+ The app's `e2e/quiz.e2e.ts`, part of the scaffold, only calls `quizTests()`.
216
220
 
217
221
  ```arc42
218
222
  :::interface
@@ -0,0 +1,5 @@
1
+ import { quizRuntimeTests } from "@lernapps/app-templates/quiz/e2e";
2
+
3
+ // The tests of the quiz runtime, which this repo runs on the template and its fixtures. Not part of the scaffold
4
+ // (lernapps.scaffold in the package.json of @lernapps/app-templates): a new app runs only quizTests(), on its content.
5
+ quizRuntimeTests();
package/quiz/package.json CHANGED
@@ -9,10 +9,11 @@
9
9
  },
10
10
  "devDependencies": {
11
11
  "@lernapps/app-templates": "file:..",
12
- "@lernapps/tooling": "^0.1.2",
12
+ "@lernapps/tooling": "0.1.3",
13
13
  "vite-plus": "1.4.0"
14
14
  },
15
15
  "overrides": {
16
+ "@lernapps/app-templates": "file:..",
16
17
  "vite": "npm:@voidzero-dev/vite-plus-core@1.4.0"
17
18
  }
18
19
  }