diff --git a/change/@microsoft-fast-html-a4161f8e-9273-42b3-9c6f-95249dd0ff2e.json b/change/@microsoft-fast-html-a4161f8e-9273-42b3-9c6f-95249dd0ff2e.json
new file mode 100644
index 00000000000..7fcb6d7e28b
--- /dev/null
+++ b/change/@microsoft-fast-html-a4161f8e-9273-42b3-9c6f-95249dd0ff2e.json
@@ -0,0 +1,7 @@
+{
+ "type": "prerelease",
+ "comment": "fix(fast-html): add errors fixture for f-template error cases",
+ "packageName": "@microsoft/fast-html",
+ "email": "7559015+janechu@users.noreply.github.com",
+ "dependentChangeType": "none"
+}
diff --git a/packages/fast-html/src/components/template.ts b/packages/fast-html/src/components/template.ts
index b7c59e808f2..08baa7d2cd3 100644
--- a/packages/fast-html/src/components/template.ts
+++ b/packages/fast-html/src/components/template.ts
@@ -239,9 +239,9 @@ class TemplateElement extends FASTElement {
);
}
- const template = this.getElementsByTagName("template").item(0);
+ const templates = this.getElementsByTagName("template");
- if (template) {
+ if (templates.length === 1) {
// Callback: Before template has been evaluated and assigned
TemplateElement.lifecycleCallbacks.templateWillUpdate?.(name);
@@ -281,6 +281,10 @@ class TemplateElement extends FASTElement {
values,
);
}
+ } else if (templates.length > 1) {
+ throw FAST.error(Message.moreThanOneTemplateProvided, {
+ name: this.name,
+ });
} else {
throw FAST.error(Message.noTemplateProvided, { name: this.name });
}
diff --git a/packages/fast-html/src/debug.ts b/packages/fast-html/src/debug.ts
index 18348fac9a3..87140bcaae2 100644
--- a/packages/fast-html/src/debug.ts
+++ b/packages/fast-html/src/debug.ts
@@ -1,3 +1,6 @@
export const debugMessages = {
- [2000 /* noTemplateProvided */]: `The first child of the must be a , this is missing from ${name}.`,
+ [2000 /* noTemplateProvided */]:
+ "The first child of the must be a , this is missing from ${name}.",
+ [2001 /* moreThanOneTemplateProvided */]:
+ "There can only be one inside the ; remove any extra elements and keep exactly one for ${name}.",
};
diff --git a/packages/fast-html/src/interfaces.ts b/packages/fast-html/src/interfaces.ts
index cf0a096fd75..7780ea9f068 100644
--- a/packages/fast-html/src/interfaces.ts
+++ b/packages/fast-html/src/interfaces.ts
@@ -4,4 +4,5 @@
*/
export const enum Message {
noTemplateProvided = 2000,
+ moreThanOneTemplateProvided = 2001,
}
diff --git a/packages/fast-html/test/fixtures/errors/entry.html b/packages/fast-html/test/fixtures/errors/entry.html
new file mode 100644
index 00000000000..af2375f44c7
--- /dev/null
+++ b/packages/fast-html/test/fixtures/errors/entry.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/fast-html/test/fixtures/errors/errors.spec.ts b/packages/fast-html/test/fixtures/errors/errors.spec.ts
new file mode 100644
index 00000000000..b33929ba23a
--- /dev/null
+++ b/packages/fast-html/test/fixtures/errors/errors.spec.ts
@@ -0,0 +1,43 @@
+import { expect, test } from "@playwright/test";
+
+test.describe("f-template errors", () => {
+ test.beforeEach(async ({ page }) => {
+ await page.addInitScript(() => {
+ (window as any).__errors = [];
+ window.addEventListener("unhandledrejection", event => {
+ event.preventDefault();
+ (window as any).__errors.push(
+ event.reason?.message ?? String(event.reason),
+ );
+ });
+ });
+ });
+
+ test("throws an error when no template element is present", async ({ page }) => {
+ await page.goto("/fixtures/errors/");
+
+ await expect
+ .poll(async () => {
+ const errors: string[] = await page.evaluate(
+ () => (window as any).__errors,
+ );
+ return errors.some(msg => msg.includes("must be a "));
+ })
+ .toBe(true);
+ });
+
+ test("throws an error when multiple template elements are present", async ({
+ page,
+ }) => {
+ await page.goto("/fixtures/errors/");
+
+ await expect
+ .poll(async () => {
+ const errors: string[] = await page.evaluate(
+ () => (window as any).__errors,
+ );
+ return errors.some(msg => msg.includes("only be one "));
+ })
+ .toBe(true);
+ });
+});
diff --git a/packages/fast-html/test/fixtures/errors/index.html b/packages/fast-html/test/fixtures/errors/index.html
new file mode 100644
index 00000000000..c5f0e533bfc
--- /dev/null
+++ b/packages/fast-html/test/fixtures/errors/index.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+ No template element provided
+ First template
+
+ No template element provided
+
+
+ First template
+ Second template
+
+
+
+
+
diff --git a/packages/fast-html/test/fixtures/errors/main.ts b/packages/fast-html/test/fixtures/errors/main.ts
new file mode 100644
index 00000000000..42c89d13649
--- /dev/null
+++ b/packages/fast-html/test/fixtures/errors/main.ts
@@ -0,0 +1,14 @@
+import { FASTElement } from "@microsoft/fast-element";
+import { TemplateElement } from "@microsoft/fast-html";
+
+class TestElementNoTemplate extends FASTElement {}
+FASTElement.define(TestElementNoTemplate, { name: "test-element-no-template" });
+
+class TestElementMultipleTemplates extends FASTElement {}
+FASTElement.define(TestElementMultipleTemplates, {
+ name: "test-element-multiple-templates",
+});
+
+TemplateElement.define({
+ name: "f-template",
+});
diff --git a/packages/fast-html/test/fixtures/errors/state.json b/packages/fast-html/test/fixtures/errors/state.json
new file mode 100644
index 00000000000..0967ef424bc
--- /dev/null
+++ b/packages/fast-html/test/fixtures/errors/state.json
@@ -0,0 +1 @@
+{}
diff --git a/packages/fast-html/test/fixtures/errors/templates.html b/packages/fast-html/test/fixtures/errors/templates.html
new file mode 100644
index 00000000000..e64819d733c
--- /dev/null
+++ b/packages/fast-html/test/fixtures/errors/templates.html
@@ -0,0 +1,7 @@
+
+ No template element provided
+
+
+ First template
+ Second template
+