Page MenuHomeSealhub

form.test.ts
No OneTemporary

form.test.ts

import Router from "@koa/router";
import axios from "axios";
import Koa, { BaseContext } from "koa";
import { Page } from "playwright";
import { Controls, Fields, Form, Mountable } from "../index.js";
import { mount } from "../mount.js";
import { locator_is_visible } from "../test_utils/locator_is_visible.js";
import { getBrowser } from "../utils/browser-creator.js";
import { assertThrowsAsync } from "../utils/utils.js";
import { FormDataValue } from "./form-types.js";
import getPort from "get-port";
import { SimpleFormField } from "./fields/simple-form-field.js";
import { expect as PlaywritghtExpect } from "@playwright/test";
const fields = {
text: new Fields.SimpleFormField(true),
};
export function form_factory(canAccessFun?: Mountable["canAccess"]): Form<typeof fields, void> {
const result = new (class extends Form<typeof fields, void> {
fields = fields;
submitButtonText = "Submit";
controls = [
new Controls.SimpleInput(fields.text, {
label: "This is a test:",
type: "password",
}),
];
async onSubmit() {
return;
}
})();
if (canAccessFun) result.canAccess = canAccessFun;
return result;
}
const port = await getPort();
console.log("Using port " + port + " for form.test.ts");
describe("form test", () => {
let page: Page;
before(async () => {
const browser = await getBrowser();
const context = await browser.newContext();
page = await context.newPage();
});
describe("basic tests", async () => {
let server: ReturnType<Koa["listen"]>;
before(async () => {
const app = new Koa();
const router = new Router();
mount(router, "/", form_factory(), true);
app.use(router.routes()).use(router.allowedMethods());
server = app.listen(port);
await page.goto(`http://localhost:${port}`);
});
after(async () => {
server.close();
});
it("does not allow to submit an empty form when there's a required field", async () => {
await page.getByRole("button", { name: "Submit", exact: true }).click();
await assertThrowsAsync(async () => {
return page.getByText("Done").click({ timeout: 500 });
});
});
it("allows to submit a form when all required fields have a value", async () => {
await page.getByPlaceholder("password").click();
await page.getByPlaceholder("password").fill("testpasswd");
await page.getByRole("button", { name: "Submit", exact: true }).click();
await page.getByText("Done").click();
});
it("does not allow submitting an empty form by circumventing HTML-based validation", async () => {
const res_axios = await axios.post(
`http://localhost:${port}`,
{
text: "",
},
{
validateStatus: (status: number) => {
if (status == 422) return true;
return false;
},
}
);
console.log(res_axios.data);
if (!res_axios.data.includes("Some fields are invalid")) {
throw new Error("when sending a empty request with axios, the error didnt appear");
}
});
});
describe("canAccess tests", async () => {
let server: ReturnType<Koa["listen"]>;
afterEach(async () => {
server.close();
});
it("allows visit when configured when canAccess returns true", async () => {
const app = new Koa();
const router = new Router();
mount(
router,
"/",
form_factory(
async (ctx: Koa.Context): Promise<{ canAccess: boolean; message: string }> => {
return { canAccess: true, message: "" };
}
),
true
);
app.use(router.routes()).use(router.allowedMethods());
server = app.listen(port);
const response = await page.goto(`http://localhost:${port}`);
if (response?.status() != 200) {
throw new Error(`Should return 200 status and it returns ${response?.status()}`);
}
});
describe("declines access when canAccess returns false", async () => {
const app = new Koa();
const router = new Router();
before(async () => {
mount(
router,
"/",
form_factory(
async (
ctx: Koa.Context
): Promise<{ canAccess: boolean; message: string }> => {
console.log("CAN ACCESS? FALSE");
return { canAccess: false, message: "" };
}
),
true
);
app.use(router.routes()).use(router.allowedMethods());
});
beforeEach(async () => {
server = app.listen(port);
});
it("prevents the form from rendering", async () => {
const response = await page.goto(`http://localhost:${port}`);
if (response?.status() != 403) {
throw new Error(
`Should return 403 status and it returns ${response?.status()}`
);
}
});
it("does not allow submitting of the form through axios", async () => {
await axios.post(
`http://localhost:${port}`,
{
text: "sample",
},
{
validateStatus: (status: number) => {
if (status == 403) return true;
return false;
},
}
);
});
});
it("passes the context to canAccess (false case)", async () => {
const app = new Koa();
const router = new Router();
mount(
router,
"/",
form_factory(
async (ctx: Koa.Context): Promise<{ canAccess: boolean; message: string }> => {
return ctx.$context && ctx.$context.user_id
? { canAccess: true, message: "" }
: { canAccess: false, message: "" };
}
),
true
);
app.use(router.routes()).use(router.allowedMethods());
server = app.listen(port);
const response = await page.goto(`http://localhost:${port}`);
if (response?.status() != 403) {
throw new Error(`Should return 403 status and it returns ${response?.status()}`);
}
});
it("passes the context to canAccess (true case)", async () => {
const app = new Koa();
const router = new Router();
router.use(async (ctx: BaseContext, next: any) => {
ctx.$context = {
user_id: "miguel",
} as any;
await next();
});
mount(
router,
"/",
form_factory(
async (ctx: Koa.Context): Promise<{ canAccess: boolean; message: string }> => {
return ctx.$context && ctx.$context.user_id
? { canAccess: true, message: "" }
: { canAccess: false, message: "" };
}
),
true
);
app.use(router.routes()).use(router.allowedMethods());
server = app.listen(port);
const response = await page.goto(`http://localhost:${port}`);
if (response?.status() != 200) {
throw new Error(`Should return 200 status and it returns ${response?.status()}`);
}
});
});
describe("validation e2e", async () => {
describe("validation message", async () => {
let server: ReturnType<Koa["listen"]>;
before(async () => {
const app = new Koa();
const router = new Router();
mount(
router,
"/",
new (class extends Form<typeof fields, void> {
fields = fields;
submitButtonText = "Submit";
controls = [
new Controls.SimpleInput(fields.text, {
label: "This is a test:",
type: "password",
}),
];
async onSubmit() {
return;
}
async validateValues(
ctx: Koa.Context,
data: Record<string, FormDataValue>
): Promise<{ valid: boolean; error: string }> {
if (data.text === "incorrect")
return {
valid: false,
error: "Incorrect input",
};
return { valid: true, error: "" };
}
})(),
true
);
app.use(router.routes()).use(router.allowedMethods());
server = app.listen(port);
await page.goto(`http://localhost:${port}`);
});
after(async () => {
server.close();
});
it("shows up when incorrect input is given", async () => {
await page.getByPlaceholder("password").click();
await page.getByPlaceholder("password").fill("incorrect");
await page.getByRole("button", { name: "Submit" }).click();
if (!(await locator_is_visible(page.getByText("Incorrect input"))))
throw new Error("validation message doens't show up when input is incorrect");
});
it("doesn't show when correct input is given", async () => {
await page.getByPlaceholder("password").click();
await page.getByPlaceholder("password").fill("correct");
await page.getByRole("button", { name: "Submit" }).click();
await assertThrowsAsync(async () => {
return page.getByText("Incorrect input").click({ timeout: 500 });
});
});
});
describe("field specific validation message", async () => {
let server: ReturnType<Koa["listen"]>;
before(async () => {
const app = new Koa();
const router = new Router();
const fields = {
text: new Fields.EmailField(true),
};
mount(
router,
"/",
new (class extends Form<typeof fields, void> {
fields = fields;
submitButtonText = "Submit";
controls = [
new Controls.SimpleInput(fields.text, {
label: "This is a test:",
type: "text",
}),
];
async onSubmit() {
return;
}
})(),
true
);
app.use(router.routes()).use(router.allowedMethods());
server = app.listen(port);
await page.goto(`http://localhost:${port}`);
});
after(async () => {
server.close();
});
it("shows up when incorrect input is given", async () => {
await page.getByPlaceholder("text").click();
await page.getByPlaceholder("text").fill("notanemail");
await page.getByRole("button", { name: "Submit" }).click();
await page.getByText("Please enter a proper email address").click();
});
it("doesn't show up when correct input is given", async () => {
await page.getByPlaceholder("text").click();
await page.getByPlaceholder("text").fill("yes@an.email");
await page.getByRole("button", { name: "Submit" }).click();
assertThrowsAsync(async () => {
return page
.getByText("Please enter a proper email address")
.click({ timeout: 500 });
});
});
});
});
describe("getInitialValues tests", async () => {
let server: ReturnType<Koa["listen"]>;
afterEach(async () => {
server.close();
});
it("fills the form with values from getInitialValues", async () => {
const app = new Koa();
const router = new Router();
const fields = {
title: new SimpleFormField(true),
};
mount(
router,
"/",
new (class extends Form<typeof fields, null> {
fields = fields;
controls = [new Controls.SimpleInput(fields.title)];
async getInitialValues() {
return { title: "Hello" };
}
onSubmit() {
return null;
}
})(),
true
);
app.use(router.routes()).use(router.allowedMethods());
server = app.listen(port);
const response = await page.goto(`http://localhost:${port}`);
if (response?.status() != 200) {
throw new Error(`Should return 200 status and it returns ${response?.status()}`);
}
await PlaywritghtExpect(page.getByLabel("title")).toHaveValue("Hello");
});
});
});

File Metadata

Mime Type
text/x-java
Expires
Wed, May 7, 19:41 (1 d, 11 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
624731
Default Alt Text
form.test.ts (10 KB)

Event Timeline