mirror of
https://github.com/thiloho/archtika.git
synced 2025-11-22 02:41:35 +01:00
Initialize playwright, fix file upload issue, show publication status and delete website dir on website deletion
This commit is contained in:
64
web-app/package-lock.json
generated
64
web-app/package-lock.json
generated
@@ -15,6 +15,7 @@
|
||||
"marked-highlight": "2.1.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "1.40.0",
|
||||
"@sveltejs/adapter-auto": "3.2.4",
|
||||
"@sveltejs/adapter-node": "5.2.2",
|
||||
"@sveltejs/kit": "2.5.22",
|
||||
@@ -515,6 +516,22 @@
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@playwright/test": {
|
||||
"version": "1.40.0",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.40.0.tgz",
|
||||
"integrity": "sha512-PdW+kn4eV99iP5gxWNSDQCbhMaDVej+RXL5xr6t04nbKLCBwYtA046t7ofoczHOm8u6c+45hpDKQVZqtqwkeQg==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright": "1.40.0"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/@polka/url": {
|
||||
"version": "1.0.0-next.25",
|
||||
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.25.tgz",
|
||||
@@ -2193,6 +2210,53 @@
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright": {
|
||||
"version": "1.40.0",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.40.0.tgz",
|
||||
"integrity": "sha512-gyHAgQjiDf1m34Xpwzaqb76KgfzYrhK7iih+2IzcOCoZWr/8ZqmdBw+t0RU85ZmfJMgtgAiNtBQ/KS2325INXw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright-core": "1.40.0"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright-core": {
|
||||
"version": "1.40.0",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.40.0.tgz",
|
||||
"integrity": "sha512-fvKewVJpGeca8t0ipM56jkVSU6Eo0RmFvQ/MaCQNDYm+sdvKkMBBWTE1FdeMqIdumRaXXjZChWHvIzCGM/tA/Q==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"playwright-core": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright/node_modules/fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.4.40",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.40.tgz",
|
||||
|
||||
@@ -6,12 +6,14 @@
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"test": "playwright test",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||
"lint": "prettier --check .",
|
||||
"format": "prettier --write ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "1.40.0",
|
||||
"@sveltejs/adapter-auto": "3.2.4",
|
||||
"@sveltejs/adapter-node": "5.2.2",
|
||||
"@sveltejs/kit": "2.5.22",
|
||||
|
||||
12
web-app/playwright.config.ts
Normal file
12
web-app/playwright.config.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { type PlaywrightTestConfig } from "@playwright/test";
|
||||
|
||||
const config: PlaywrightTestConfig = {
|
||||
webServer: {
|
||||
command: "npm run build && npm run preview",
|
||||
port: 4173
|
||||
},
|
||||
testDir: "tests",
|
||||
testMatch: /(.+\.)?(test|spec)\.ts/
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -1,3 +1,5 @@
|
||||
import { dev } from "$app/environment";
|
||||
|
||||
export const API_BASE_PREFIX = dev ? "http://localhost:3000" : `${process.env.ORIGIN}/api`;
|
||||
export const API_BASE_PREFIX = dev
|
||||
? "http://localhost:3000"
|
||||
: `${process.env.ORIGIN ? `${process.env.ORIGIN}/api` : "http://localhost:3000"}`;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import type { Actions, PageServerLoad } from "./$types";
|
||||
import { API_BASE_PREFIX } from "$lib/server/utils";
|
||||
import { rm } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
|
||||
export const load: PageServerLoad = async ({ fetch, cookies, url, locals }) => {
|
||||
const searchQuery = url.searchParams.get("website_search_query");
|
||||
@@ -130,6 +132,11 @@ export const actions: Actions = {
|
||||
return { success: false, message: response.message };
|
||||
}
|
||||
|
||||
await rm(join("/", "var", "www", "archtika-websites", data.get("id") as string), {
|
||||
recursive: true,
|
||||
force: true
|
||||
});
|
||||
|
||||
return { success: true, message: "Successfully deleted website" };
|
||||
}
|
||||
};
|
||||
|
||||
@@ -49,22 +49,27 @@ export const actions: Actions = {
|
||||
const data = await request.formData();
|
||||
const faviconFile = data.get("favicon") as File;
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
"Content-Type": "application/octet-stream",
|
||||
Authorization: `Bearer ${cookies.get("session_token")}`,
|
||||
Accept: "application/vnd.pgrst.object+json",
|
||||
"X-Website-Id": params.websiteId
|
||||
};
|
||||
|
||||
if (faviconFile) {
|
||||
headers["X-Mimetype"] = faviconFile.type;
|
||||
headers["X-Original-Filename"] = faviconFile.name;
|
||||
}
|
||||
|
||||
const uploadedImageData = await fetch(`${API_BASE_PREFIX}/rpc/upload_file`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/octet-stream",
|
||||
Authorization: `Bearer ${cookies.get("session_token")}`,
|
||||
Accept: "application/vnd.pgrst.object+json",
|
||||
"X-Website-Id": params.websiteId,
|
||||
"X-Mimetype": faviconFile.type,
|
||||
"X-Original-Filename": faviconFile.name
|
||||
},
|
||||
body: await faviconFile.arrayBuffer()
|
||||
headers,
|
||||
body: faviconFile ? await faviconFile.arrayBuffer() : null
|
||||
});
|
||||
|
||||
const uploadedImage = await uploadedImageData.json();
|
||||
|
||||
if (!uploadedImageData.ok && faviconFile.size > 0) {
|
||||
if (!uploadedImageData.ok && (faviconFile?.size ?? 0 > 0)) {
|
||||
return { success: false, message: uploadedImage.message };
|
||||
}
|
||||
|
||||
@@ -95,22 +100,27 @@ export const actions: Actions = {
|
||||
const data = await request.formData();
|
||||
const logoImage = data.get("logo-image") as File;
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
"Content-Type": "application/octet-stream",
|
||||
Authorization: `Bearer ${cookies.get("session_token")}`,
|
||||
Accept: "application/vnd.pgrst.object+json",
|
||||
"X-Website-Id": params.websiteId
|
||||
};
|
||||
|
||||
if (logoImage) {
|
||||
headers["X-Mimetype"] = logoImage.type;
|
||||
headers["X-Original-Filename"] = logoImage.name;
|
||||
}
|
||||
|
||||
const uploadedImageData = await fetch(`${API_BASE_PREFIX}/rpc/upload_file`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/octet-stream",
|
||||
Authorization: `Bearer ${cookies.get("session_token")}`,
|
||||
Accept: "application/vnd.pgrst.object+json",
|
||||
"X-Website-Id": params.websiteId,
|
||||
"X-Mimetype": logoImage.type,
|
||||
"X-Original-Filename": logoImage.name
|
||||
},
|
||||
body: await logoImage.arrayBuffer()
|
||||
headers,
|
||||
body: logoImage ? await logoImage.arrayBuffer() : null
|
||||
});
|
||||
|
||||
const uploadedImage = await uploadedImageData.json();
|
||||
|
||||
if (!uploadedImageData.ok && logoImage.size > 0) {
|
||||
if (!uploadedImageData.ok && (logoImage?.size ?? 0 > 0)) {
|
||||
return { success: false, message: uploadedImage.message };
|
||||
}
|
||||
|
||||
|
||||
@@ -123,12 +123,7 @@
|
||||
<div class="file-field">
|
||||
<label>
|
||||
Logo image:
|
||||
<input
|
||||
type="file"
|
||||
name="logo-image"
|
||||
accept={ALLOWED_MIME_TYPES.join(", ")}
|
||||
required={data.header.logo_type === "image"}
|
||||
/>
|
||||
<input type="file" name="logo-image" accept={ALLOWED_MIME_TYPES.join(", ")} />
|
||||
</label>
|
||||
{#if data.header.logo_image}
|
||||
<Modal id="preview-logo-header-{data.header.website_id}" text="Preview">
|
||||
|
||||
@@ -34,22 +34,27 @@ export const actions: Actions = {
|
||||
const data = await request.formData();
|
||||
const coverFile = data.get("cover-image") as File;
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
"Content-Type": "application/octet-stream",
|
||||
Authorization: `Bearer ${cookies.get("session_token")}`,
|
||||
Accept: "application/vnd.pgrst.object+json",
|
||||
"X-Website-Id": params.websiteId
|
||||
};
|
||||
|
||||
if (coverFile) {
|
||||
headers["X-Mimetype"] = coverFile.type;
|
||||
headers["X-Original-Filename"] = coverFile.name;
|
||||
}
|
||||
|
||||
const uploadedImageData = await fetch(`${API_BASE_PREFIX}/rpc/upload_file`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/octet-stream",
|
||||
Authorization: `Bearer ${cookies.get("session_token")}`,
|
||||
Accept: "application/vnd.pgrst.object+json",
|
||||
"X-Website-Id": params.websiteId,
|
||||
"X-Mimetype": coverFile.type,
|
||||
"X-Original-Filename": coverFile.name
|
||||
},
|
||||
body: await coverFile.arrayBuffer()
|
||||
headers,
|
||||
body: coverFile ? await coverFile.arrayBuffer() : null
|
||||
});
|
||||
|
||||
const uploadedImage = await uploadedImageData.json();
|
||||
|
||||
if (!uploadedImageData.ok && coverFile.size > 0) {
|
||||
if (!uploadedImageData.ok && (coverFile?.size ?? 0 > 0)) {
|
||||
return { success: false, message: uploadedImage.message };
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,22 @@ export const actions: Actions = {
|
||||
const websiteOverview = await websiteOverviewData.json();
|
||||
generateStaticFiles(websiteOverview, false);
|
||||
|
||||
const res = await fetch(`${API_BASE_PREFIX}/website?id=eq.${params.websiteId}`, {
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${cookies.get("session_token")}`
|
||||
},
|
||||
body: JSON.stringify({
|
||||
is_published: true
|
||||
})
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
const response = await res.json();
|
||||
return { success: false, message: response.message };
|
||||
}
|
||||
|
||||
return { success: true, message: "Successfully published website" };
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
import type { ActionData, PageServerData } from "./$types";
|
||||
|
||||
const { data, form }: { data: PageServerData; form: ActionData } = $props();
|
||||
|
||||
const prodWebsiteUrl = data.websitePreviewUrl.replace("/previews", "");
|
||||
</script>
|
||||
|
||||
<SuccessOrError success={form?.success} message={form?.message} />
|
||||
@@ -28,5 +30,18 @@
|
||||
<form method="POST" action="?/publishWebsite" use:enhance>
|
||||
<button type="submit">Publish</button>
|
||||
</form>
|
||||
|
||||
{#if data.website.is_published}
|
||||
<section>
|
||||
<h3>
|
||||
<a href="#publication-status">Publication status</a>
|
||||
</h3>
|
||||
<p>
|
||||
Your website is published at:
|
||||
<br />
|
||||
<a href={prodWebsiteUrl}>{prodWebsiteUrl}</a>
|
||||
</p>
|
||||
</section>
|
||||
{/if}
|
||||
</section>
|
||||
</WebsiteEditor>
|
||||
|
||||
68
web-app/tests/account.spec.ts
Normal file
68
web-app/tests/account.spec.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
|
||||
test("Register", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await page.getByRole("link", { name: "Register" }).click();
|
||||
await page.getByLabel("Username:").click();
|
||||
await page.getByLabel("Username:").fill("archtika-test");
|
||||
await page.getByLabel("Password:").click();
|
||||
await page.getByLabel("Password:").fill("T3stuser??!!");
|
||||
await page.getByRole("button", { name: "Submit" }).click();
|
||||
await expect(page.getByText("Successfully registered, you")).toBeVisible();
|
||||
});
|
||||
|
||||
test("Login", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await page.getByRole("link", { name: "Login" }).click();
|
||||
await page.getByLabel("Username:").click();
|
||||
await page.getByLabel("Username:").fill("archtika-test");
|
||||
await page.getByLabel("Password:").click();
|
||||
await page.getByLabel("Password:").fill("T3stuser??!!");
|
||||
await page.getByRole("button", { name: "Submit" }).click();
|
||||
await expect(page.getByRole("heading", { name: "Dashboard" })).toBeVisible();
|
||||
});
|
||||
|
||||
test("Logout", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await page.getByRole("link", { name: "Login" }).click();
|
||||
await page.getByLabel("Username:").click();
|
||||
await page.getByLabel("Username:").fill("archtika-test");
|
||||
await page.getByLabel("Password:").click();
|
||||
await page.getByLabel("Password:").fill("T3stuser??!!");
|
||||
await page.getByRole("button", { name: "Submit" }).click();
|
||||
await expect(page.getByRole("heading", { name: "Dashboard" })).toBeVisible();
|
||||
await page.getByRole("link", { name: "Account" }).click();
|
||||
await page.getByRole("button", { name: "Logout" }).click();
|
||||
await expect(page.getByRole("heading", { name: "Login" })).toBeVisible();
|
||||
});
|
||||
|
||||
test("Delete account", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await page.getByRole("link", { name: "Login" }).click();
|
||||
await page.getByLabel("Username:").click();
|
||||
await page.getByLabel("Username:").fill("archtika-test");
|
||||
await page.getByLabel("Password:").click();
|
||||
await page.getByLabel("Password:").fill("T3stuser??!!");
|
||||
await page.getByRole("button", { name: "Submit" }).click();
|
||||
await expect(page.getByRole("heading", { name: "Dashboard" })).toBeVisible();
|
||||
await page.getByRole("link", { name: "Account" }).click();
|
||||
await page.getByRole("button", { name: "Delete account" }).click();
|
||||
await page.getByLabel("Password:").click();
|
||||
await page.getByLabel("Password:").fill("T3stuser??!!");
|
||||
await page
|
||||
.locator("#delete-account-modal")
|
||||
.getByRole("button", { name: "Delete account" })
|
||||
.click();
|
||||
await expect(page.getByRole("heading", { name: "Login" })).toBeVisible();
|
||||
});
|
||||
|
||||
test("Register after account deletion", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await page.getByRole("link", { name: "Register" }).click();
|
||||
await page.getByLabel("Username:").click();
|
||||
await page.getByLabel("Username:").fill("archtika-test");
|
||||
await page.getByLabel("Password:").click();
|
||||
await page.getByLabel("Password:").fill("T3stuser??!!");
|
||||
await page.getByRole("button", { name: "Submit" }).click();
|
||||
await expect(page.getByText("Successfully registered, you")).toBeVisible();
|
||||
});
|
||||
Reference in New Issue
Block a user