diff --git a/test/basic.test.ts b/test/basic.test.ts
deleted file mode 100644
index 215a0be..0000000
--- a/test/basic.test.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { describe, it, expect } from "vitest";
-import { fileURLToPath } from "node:url";
-import { setup, $fetch } from "@nuxt/test-utils";
-
-describe("ssr", async () => {
- await setup({
- rootDir: fileURLToPath(new URL("./fixtures/basic", import.meta.url)),
- });
-
- it("renders the index page", async () => {
- // Get response to a server-rendered page with `$fetch`.
- const html = await $fetch("/");
- expect(html).toContain("
basic
");
- });
-});
diff --git a/test/build.test.ts b/test/build.test.ts
new file mode 100644
index 0000000..9e4d91c
--- /dev/null
+++ b/test/build.test.ts
@@ -0,0 +1,36 @@
+import { describe, it, expect } from "vitest";
+import { fileURLToPath } from "node:url";
+import { buildNuxtApp, getOutputFiles } from "@/test/utils";
+
+const ROOT_DIR = fileURLToPath(new URL("./fixtures/basic", import.meta.url));
+
+//TODO: Explore how we can test the generated HTML file
+// Need also to investigate if the programmatic build has a different output than the CLI build
+describe("nuxt-singlefile", async () => {
+ await buildNuxtApp({
+ rootDir: ROOT_DIR,
+ });
+
+ it("builds without throwing an error", async () => {
+ expect(true).toBe(true);
+ });
+ it("generates an html file", async () => {
+ const outputFiles = await getOutputFiles({
+ rootDir: ROOT_DIR,
+ });
+
+ expect(outputFiles).toSatisfy((files: string[]) =>
+ files.some((file) => file.includes("index.html")),
+ );
+ });
+ it("generates only one html file", async () => {
+ const outputFiles = await getOutputFiles({
+ rootDir: ROOT_DIR,
+ });
+
+ expect(outputFiles).toSatisfy(
+ (files: string[]) =>
+ files.filter((file) => file.includes(".html")).length === 1,
+ );
+ });
+});
diff --git a/test/src/runtime/utils/generateInlinedStringForTag.spec.ts b/test/src/runtime/utils/generateInlinedStringForTag.spec.ts
new file mode 100644
index 0000000..841a9dd
--- /dev/null
+++ b/test/src/runtime/utils/generateInlinedStringForTag.spec.ts
@@ -0,0 +1,22 @@
+import { describe, it, expect } from "vitest";
+import { generateInlinedStringForTag } from "@/src/runtime/utils/generateInlinedStringForTag";
+
+describe("generateInlinedStringForTag", () => {
+ it("should generate an inlined script tag with the given content", () => {
+ const content = "console.log('Hello, world!');";
+ const type = "script";
+
+ const result = generateInlinedStringForTag(content, type);
+
+ expect(result).toBe(``);
+ });
+
+ it("should generate an inlined style tag with the given content", () => {
+ const content = "body { background-color: #f0f0f0; }";
+ const type = "style";
+
+ const result = generateInlinedStringForTag(content, type);
+
+ expect(result).toBe(``);
+ });
+});
diff --git a/test/src/runtime/utils/generateSingleFileRenderContext.spec.ts b/test/src/runtime/utils/generateSingleFileRenderContext.spec.ts
new file mode 100644
index 0000000..7558ac0
--- /dev/null
+++ b/test/src/runtime/utils/generateSingleFileRenderContext.spec.ts
@@ -0,0 +1,130 @@
+import { describe, it, expect, vi, afterEach } from "vitest";
+import { generateSingleFileRenderContext } from "@/src/runtime/utils/generateSingleFileRenderContext";
+import type { NuxtRenderHTMLContext } from "nuxt/dist/core/runtime/nitro/renderer";
+
+const CORRECT_PATH_TO_FILES = "/path/to/files";
+const FIRST_JS_FILE = "test-file.js";
+const SECOND_JS_FILE = "index2.js";
+const FIRST_CSS_FILE = "index.css";
+const SECOND_CSS_FILE = "test-file2.css";
+
+const BASIC_HTML_RENDER_CONTEXT: NuxtRenderHTMLContext = {
+ island: false,
+ htmlAttrs: [],
+ head: [
+ ``,
+ ``,
+ ],
+ bodyAttrs: [],
+ bodyPrepend: [],
+ body: [""],
+ bodyAppend: [
+ '\n',
+ ],
+};
+
+describe("generateSingleFileRenderContext", () => {
+ vi.mock("node:fs/promises", async () => ({
+ ...(await vi.importActual(
+ "node:fs/promises",
+ )),
+ readFile: vi.fn(async (...params: Array) =>
+ params[0].startsWith(CORRECT_PATH_TO_FILES)
+ ? Promise.resolve(`mocked file content for ${params[0]}`)
+ : Promise.reject(`invalid path: ${params[0]}`),
+ ),
+ }));
+
+ afterEach(() => {
+ vi.restoreAllMocks();
+ });
+
+ it("should generate a new render context with inlined head content", async () => {
+ const baseHtmlRenderContext = BASIC_HTML_RENDER_CONTEXT;
+
+ const result = await generateSingleFileRenderContext(
+ baseHtmlRenderContext,
+ CORRECT_PATH_TO_FILES,
+ );
+
+ expect(result).toEqual({
+ ...baseHtmlRenderContext,
+ head: expect.arrayContaining([
+ expect.stringContaining(``,
+ ``,
+ ``,
+ ``,
+ ],
+ };
+
+ const result = await generateSingleFileRenderContext(
+ baseHtmlRenderContext,
+ CORRECT_PATH_TO_FILES,
+ );
+
+ expect(result).toEqual({
+ ...baseHtmlRenderContext,
+ head: expect.arrayContaining([
+ '',
+ '',
+ expect.stringContaining(``;
+ const pathToFiles = CORRECT_PATH_TO_FILES;
+ const type = "script";
+
+ const result = await getInlineContentForTagsType({
+ baseHtml,
+ pathToFiles,
+ type,
+ });
+
+ expect(result).toEqual(
+ expect.arrayContaining([
+ expect.objectContaining({
+ tagString: baseHtml,
+ content: expect.stringContaining(`/${FIRST_JS_FILE}`),
+ type: type,
+ }),
+ ]),
+ );
+ });
+
+ it("should return the correct inline content for multiple script tags", async () => {
+ const baseHtml = `
+
+
+ `;
+ const pathToFiles = CORRECT_PATH_TO_FILES;
+ const type = "script";
+
+ const result = await getInlineContentForTagsType({
+ baseHtml,
+ pathToFiles,
+ type,
+ });
+
+ expect(result).toEqual(
+ expect.arrayContaining([
+ expect.objectContaining({
+ tagString: ``,
+ content: expect.stringContaining(`/${FIRST_JS_FILE}`),
+ type: type,
+ }),
+ expect.objectContaining({
+ tagString: ``,
+ content: expect.stringContaining(`/${SECOND_JS_FILE}`),
+ type: type,
+ }),
+ ]),
+ );
+ });
+
+ it("should return the correct inline content for a single style tag", async () => {
+ const baseHtml = ``;
+ const pathToFiles = CORRECT_PATH_TO_FILES;
+ const type = "style";
+
+ const result = await getInlineContentForTagsType({
+ baseHtml,
+ pathToFiles,
+ type,
+ });
+
+ expect(result).toEqual(
+ expect.arrayContaining([
+ expect.objectContaining({
+ tagString: baseHtml,
+ content: expect.stringContaining(`/${FIRST_CSS_FILE}`),
+ type: type,
+ }),
+ ]),
+ );
+ });
+
+ it("should return the correct inline content for multiple style tags", async () => {
+ const baseHtml = `
+
+
+ `;
+ const pathToFiles = CORRECT_PATH_TO_FILES;
+ const type = "style";
+
+ const result = await getInlineContentForTagsType({
+ baseHtml,
+ pathToFiles,
+ type,
+ });
+
+ expect(result).toEqual(
+ expect.arrayContaining([
+ expect.objectContaining({
+ tagString: ``,
+ content: expect.stringContaining(`/${FIRST_CSS_FILE}`),
+ type: type,
+ }),
+ expect.objectContaining({
+ tagString: ``,
+ content: expect.stringContaining(`/${SECOND_CSS_FILE}`),
+ type: type,
+ }),
+ ]),
+ );
+ });
+
+ it("should return the correct inline content for mixed tags", async () => {
+ const baseHtml = `
+
+
+
+
+
+
+ `;
+ const pathToFiles = CORRECT_PATH_TO_FILES;
+ const type = "style";
+
+ const result = await getInlineContentForTagsType({
+ baseHtml,
+ pathToFiles,
+ type,
+ });
+
+ expect(result).toEqual(
+ expect.arrayContaining([
+ expect.objectContaining({
+ tagString: ``,
+ content: expect.stringContaining(`/${FIRST_CSS_FILE}`),
+ type: type,
+ }),
+ expect.objectContaining({
+ tagString: ``,
+ content: expect.stringContaining(`/${SECOND_CSS_FILE}`),
+ type: type,
+ }),
+ ]),
+ );
+ });
+
+ it("should return an empty array if no tags of the given type are found", async () => {
+ const baseHtml = ``;
+ const pathToFiles = CORRECT_PATH_TO_FILES;
+ const type = "script";
+
+ const result = await getInlineContentForTagsType({
+ baseHtml,
+ pathToFiles,
+ type,
+ });
+
+ expect(result).toEqual([]);
+ });
+
+ it("should throw an error if the path to files is invalid", async () => {
+ const baseHtml = ``;
+ const pathToFiles = "/invalid/path";
+ const type = "script";
+
+ await expect(
+ getInlineContentForTagsType({ baseHtml, pathToFiles, type }),
+ ).rejects.toThrow(expect.stringContaining(pathToFiles));
+ });
+
+ it("should throw an error if the type is invalid", async () => {
+ const baseHtml = ``;
+ const pathToFiles = CORRECT_PATH_TO_FILES;
+ const type = "invalidType";
+
+ await expect(
+ // @ts-expect-error
+ getInlineContentForTagsType({ baseHtml, pathToFiles, type }),
+ ).rejects.toThrow(`invalid type: ${type}`);
+ });
+});
diff --git a/test/src/runtime/utils/getInlinedHeadContent.spec.ts b/test/src/runtime/utils/getInlinedHeadContent.spec.ts
new file mode 100644
index 0000000..dc0708a
--- /dev/null
+++ b/test/src/runtime/utils/getInlinedHeadContent.spec.ts
@@ -0,0 +1,106 @@
+import { describe, it, expect, vi, afterEach } from "vitest";
+import { getInlinedHeadContent } from "@/src/runtime/utils/getInlinedHeadContent";
+
+const CORRECT_PATH_TO_FILES = "/path/to/files";
+const FIRST_JS_FILE = "test-file.js";
+const SECOND_JS_FILE = "index2.js";
+const FIRST_CSS_FILE = "index.css";
+const SECOND_CSS_FILE = "test-file2.css";
+
+describe("getInlinedHeadContent", () => {
+ vi.mock("node:fs/promises", async () => ({
+ ...(await vi.importActual(
+ "node:fs/promises",
+ )),
+ readFile: vi.fn(async (...params: Array) =>
+ params[0].startsWith(CORRECT_PATH_TO_FILES)
+ ? Promise.resolve(`mocked file content for ${params[0]}`)
+ : Promise.reject(`invalid path: ${params[0]}`),
+ ),
+ }));
+
+ afterEach(() => {
+ vi.restoreAllMocks();
+ });
+
+ it("should inline the content of each tag type in the head HTML", async () => {
+ const head = [
+ ``,
+ ``,
+ ];
+
+ const pathToFiles = CORRECT_PATH_TO_FILES;
+
+ const result = await getInlinedHeadContent(head, pathToFiles);
+
+ expect(result).toEqual(
+ expect.arrayContaining([
+ expect.stringContaining(``,
+ ``,
+ ``,
+ ``,
+ ];
+ const pathToFiles = CORRECT_PATH_TO_FILES;
+
+ const result = await getInlinedHeadContent(head, pathToFiles);
+
+ expect(result).toEqual(
+ expect.arrayContaining([
+ '',
+ '',
+ expect.stringContaining(``,
+ ``,
+ ];
+ const pathToFiles = "/invalid/path";
+
+ await expect(getInlinedHeadContent(head, pathToFiles)).rejects.toThrow(
+ expect.stringContaining(pathToFiles),
+ );
+ });
+});
diff --git a/test/utils/index.ts b/test/utils/index.ts
new file mode 100644
index 0000000..4fcfa77
--- /dev/null
+++ b/test/utils/index.ts
@@ -0,0 +1,22 @@
+import { resolve } from "node:path";
+import { loadNuxt, buildNuxt } from "@nuxt/kit";
+import { globby } from "globby";
+import { memoize } from "lodash-es";
+
+export const buildNuxtApp = async ({ rootDir }: { rootDir: string }) => {
+ const nuxt = await loadNuxt({
+ cwd: rootDir,
+ ready: true,
+ });
+ await buildNuxt(nuxt);
+ return nuxt;
+};
+
+export const rawGetOutputFiles = async ({ rootDir }: { rootDir: string }) => {
+ const outputFilesPath = resolve(rootDir, ".output");
+ const outputFiles = await globby(outputFilesPath);
+
+ return outputFiles;
+};
+
+export const getOutputFiles = memoize(rawGetOutputFiles);