111 lines
3.5 KiB
TypeScript
111 lines
3.5 KiB
TypeScript
/// <reference types="cypress" />
|
|
|
|
Cypress.env("AUTO_LOGIN", false);
|
|
|
|
describe("sign-in page", () => {
|
|
after(() => {
|
|
Cypress.env("AUTO_LOGIN", true);
|
|
});
|
|
|
|
beforeEach(() => {
|
|
cy.clearCookies();
|
|
cy.clearLocalStorage();
|
|
|
|
cy.intercept("POST", "**/api/proxy/profile/login*", (req) => {
|
|
req.reply({
|
|
delay: 2500,
|
|
statusCode: 200,
|
|
body: {
|
|
success: true,
|
|
message: "ok",
|
|
data: {
|
|
access_token: "e2e-access-token",
|
|
refresh_token: "e2e-refresh-token",
|
|
expires_at: Date.now() + 60_000,
|
|
user: {
|
|
id: "507f1f77bcf86cd799439011",
|
|
username: "tester",
|
|
email: "tester@example.com",
|
|
role: "admin",
|
|
},
|
|
},
|
|
},
|
|
});
|
|
}).as("loginRequest");
|
|
|
|
cy.visit("/auth/sign-in");
|
|
cy.location("pathname").should("eq", "/auth/sign-in");
|
|
});
|
|
|
|
it("keeps the sign-in box centered and visible in viewport", () => {
|
|
cy.get("div[class*='max-w-'][class*='shadow-theme-xs'][class*='rounded-2xl']")
|
|
.first()
|
|
.should("be.visible")
|
|
.then(($card) => {
|
|
const rect = $card[0].getBoundingClientRect();
|
|
|
|
cy.window().then((win) => {
|
|
const viewportCenterX = win.innerWidth / 2;
|
|
const viewportCenterY = win.innerHeight / 2;
|
|
const cardCenterX = rect.left + rect.width / 2;
|
|
const cardCenterY = rect.top + rect.height / 2;
|
|
|
|
expect(rect.top).to.be.gte(0);
|
|
expect(rect.left).to.be.gte(0);
|
|
expect(rect.bottom).to.be.lte(win.innerHeight);
|
|
expect(rect.right).to.be.lte(win.innerWidth);
|
|
expect(Math.abs(cardCenterX - viewportCenterX)).to.be.lessThan(80);
|
|
expect(Math.abs(cardCenterY - viewportCenterY)).to.be.lessThan(100);
|
|
});
|
|
});
|
|
});
|
|
|
|
it("toggles theme correctly", () => {
|
|
cy.get("html").should("not.have.class", "dark");
|
|
cy.contains("button", "Switch to dark mode").click();
|
|
cy.get("html").should("have.class", "dark");
|
|
|
|
cy.contains("button", "Switch to light mode").click();
|
|
cy.get("html").should("not.have.class", "dark");
|
|
});
|
|
|
|
it("shows required errors under each field and does not call login API", () => {
|
|
cy.contains('button[type="submit"]', "Sign in").click();
|
|
|
|
cy.get("p.text-error")
|
|
.should("have.length", 2)
|
|
.each(($message) => {
|
|
expect($message.text().trim()).to.eq("This field is required");
|
|
});
|
|
cy.get("@loginRequest.all").should("have.length", 0);
|
|
});
|
|
|
|
it("shows and hides password value when lock icon is clicked", () => {
|
|
cy.get('input[name="password"]').as("passwordInput");
|
|
cy.get("@passwordInput").should("have.attr", "type", "password");
|
|
|
|
cy.get('button[aria-label="Show password"]').click();
|
|
cy.get("@passwordInput").should("have.attr", "type", "text");
|
|
|
|
cy.get('button[aria-label="Hide password"]').click();
|
|
cy.get("@passwordInput").should("have.attr", "type", "password");
|
|
});
|
|
|
|
it("shows default button text first, then spinner while submitting", () => {
|
|
cy.contains('button[type="submit"]', "Sign in")
|
|
.as("submitButton")
|
|
.should("be.visible")
|
|
.and("not.be.disabled");
|
|
|
|
cy.get('input[name="username"]').type("tester");
|
|
cy.get('input[name="password"]').type("Secret123!");
|
|
|
|
cy.get("@submitButton").click();
|
|
cy.get('button[type="submit"]')
|
|
.find("div.animate-spin", { timeout: 10000 })
|
|
.should("exist");
|
|
cy.get('button[type="submit"]').should("not.contain", "Sign in");
|
|
});
|
|
|
|
});
|