Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
205 changes: 21 additions & 184 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

62 changes: 62 additions & 0 deletions websites/resume-builder/cypress.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { defineConfig } from "cypress";
import { remove, copy, ensureDir } from "fs-extra";
import { resolve } from "node:path";
import simpleGit from "simple-git";

async function resetData(fixture?: string) {
const testContentDir = resolve("test-content");
await remove(testContentDir);
if (fixture) {
await copy(
resolve("cypress", "fixtures", "test-content", fixture),
testContentDir,
);
} else {
await ensureDir(testContentDir);
}
return null;
}

async function copyFixtures(fixtureName: string) {
const testContentDir = resolve("test-content");
const fixtureDir = resolve(
"cypress",
"fixtures",
"test-content",
fixtureName,
);
await remove(fixtureDir);
await copy(testContentDir, fixtureDir);
return null;
}

export default defineConfig({
e2e: {
baseUrl: "http://localhost:3000",
defaultCommandTimeout: 10000,
setupNodeEvents(on) {
on("task", {
async getContentGitLog() {
const git = simpleGit(resolve("test-content"));
const log = await git.log();
return log.all.map((item) => item.message);
},
async initializeContentGit() {
const testContentDir = resolve("test-content");
await ensureDir(testContentDir);
const git = simpleGit(testContentDir);
await git.init();
await git
.add(".")
.commit("Initial commit", { "--allow-empty": null });
return null;
},
resetData,
copyFixtures,
});
},
retries: {
runMode: 2,
},
},
});
161 changes: 161 additions & 0 deletions websites/resume-builder/cypress/e2e/create.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
describe("Resume Create Operations", function () {
describe("Create Operations", function () {
beforeEach(function () {
cy.resetData();
cy.visit("/");
});

it("should display empty state when no resumes exist", function () {
cy.findByText("There are no resumes yet.");
});

it("should create a new resume with required fields only", function () {
cy.visit("/new-resume");

cy.findByLabelText("Company").type("Acme Corp");
cy.findByLabelText("Job").type("Software Engineer");

cy.findByRole("button", { name: "Submit" }).click();

// Should redirect to view page
cy.url().should("include", "/resume/acme-corp-software-engineer");
cy.findByText("Software Engineer");
cy.findByText("Acme Corp");
});

it("should auto-generate slug from company and job", function () {
cy.visit("/new-resume");

cy.findByLabelText("Company").type("Big Tech");
cy.findByLabelText("Job").type("Staff Engineer");

cy.findByRole("button", { name: "Submit" }).click();

cy.url().should("include", "/resume/big-tech-staff-engineer");
});

it("should use custom slug when provided", function () {
cy.visit("/new-resume");

cy.findByLabelText("Company").type("Startup Inc");
cy.findByLabelText("Job").type("CTO");
cy.findByLabelText("Slug").type("my-custom-resume-slug");

cy.findByRole("button", { name: "Submit" }).click();

cy.url().should("include", "/resume/my-custom-resume-slug");
});

it("should create a resume with all applicant fields", function () {
cy.visit("/new-resume");

cy.findByLabelText("Name").type("Jane Doe");
cy.findByLabelText("Email").type("jane@example.com");
cy.findByLabelText("Phone").type("555-1234");
cy.findByLabelText("Address").type("123 Main St");
cy.findByLabelText("Github").type("janedoe");
cy.findByLabelText("LinkedIn").type("janedoe");
cy.findByLabelText("Website").type("janedoe.dev");
cy.findByLabelText("Company").type("Widgets Co");
cy.findByLabelText("Job").type("Designer");

cy.findByRole("button", { name: "Submit" }).click();

// Should redirect to view page with contact info
cy.url().should("include", "/resume/widgets-co-designer");
cy.findByText("Jane Doe");
cy.findByText("jane@example.com");
cy.findByText("555-1234");
cy.findByText("123 Main St");
cy.findByText(/github.com\/janedoe/);
cy.findByText(/linkedin.com\/in\/janedoe/);
cy.findByText("janedoe.dev");
});

it("should show the new resume in the list on homepage", function () {
cy.visit("/new-resume");

cy.findByLabelText("Company").type("Listed Corp");
cy.findByLabelText("Job").type("Engineer");
cy.findByRole("button", { name: "Submit" }).click();

cy.visit("/");
cy.findByText("Listed Corp");
});

it("should show validation error when required fields missing", function () {
cy.visit("/new-resume");

cy.findByRole("button", { name: "Submit" }).click();

cy.findByText("Failed to create Resume.");
});

it("should show validation error when only company is provided", function () {
cy.visit("/new-resume");

cy.findByLabelText("Company").type("Only Company");

cy.findByRole("button", { name: "Submit" }).click();

cy.findByText("Failed to create Resume.");
});

it("should show validation error when only job is provided", function () {
cy.visit("/new-resume");

cy.findByLabelText("Job").type("Only Job");

cy.findByRole("button", { name: "Submit" }).click();

cy.findByText("Failed to create Resume.");
});
});

describe("Rapid Operations", function () {
beforeEach(function () {
cy.resetData();
});

it("should handle creating multiple resumes in sequence", function () {
for (let i = 1; i <= 3; i++) {
cy.visit("/new-resume");
cy.findByLabelText("Company").type(`Company ${i}`);
cy.findByLabelText("Job").type("Engineer");
cy.findByRole("button", { name: "Submit" }).click();
cy.url().should("include", `/resume/company-${i}-engineer`);
}

cy.visit("/");
cy.findByText("Company 3");
cy.findByText("Company 2");
cy.findByText("Company 1");
});

it("should handle create then immediate edit", function () {
cy.visit("/new-resume");
cy.findByLabelText("Company").type("Quick Create Co");
cy.findByLabelText("Job").type("Tester");
cy.findByRole("button", { name: "Submit" }).click();

cy.findByRole("link", { name: "Edit" }).click();
cy.findByLabelText("Company").clear();
cy.findByLabelText("Company").type("Quick Edit Co");
cy.findByRole("button", { name: "Submit" }).click();

cy.findByText("Quick Edit Co");
});

it("should handle create then immediate delete", function () {
cy.visit("/new-resume");
cy.findByLabelText("Company").type("Quick Delete Co");
cy.findByLabelText("Job").type("Manager");
cy.findByRole("button", { name: "Submit" }).click();

cy.findByRole("button", { name: "Delete" }).click();

cy.url().should("eq", Cypress.config().baseUrl + "/");
cy.findByText("There are no resumes yet.");
});
});
});
44 changes: 44 additions & 0 deletions websites/resume-builder/cypress/e2e/delete.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
describe("Resume Delete Operations", function () {
describe("Delete Operations", function () {
beforeEach(function () {
cy.resetData("one-resume");
});

it("should delete resume and redirect to homepage", function () {
cy.visit("/resume/acme-corp-engineer");
cy.findByRole("button", { name: "Delete" }).click();

cy.url().should("eq", Cypress.config().baseUrl + "/");
});

it("should show empty state after deleting the only resume", function () {
cy.visit("/resume/acme-corp-engineer");
cy.findByRole("button", { name: "Delete" }).click();

cy.findByText("There are no resumes yet.");
});

it("should not show deleted resume on homepage", function () {
cy.visit("/resume/acme-corp-engineer");
cy.findByRole("button", { name: "Delete" }).click();

cy.findByText("Acme Corp").should("not.exist");
});

it("should return 404 after deleting resume", function () {
cy.visit("/resume/acme-corp-engineer");
cy.findByRole("button", { name: "Delete" }).click();

// Confirm redirect completed
cy.url().should("eq", Cypress.config().baseUrl + "/");

// Deleted slug should return 404
cy.request({
url: "/resume/acme-corp-engineer",
failOnStatusCode: false,
})
.its("status")
.should("equal", 404);
});
});
});
83 changes: 83 additions & 0 deletions websites/resume-builder/cypress/e2e/git.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
describe("Git Integration", function () {
beforeEach(function () {
cy.resetData();
cy.initializeContentGit();
});

it("should create git commit when creating a resume", function () {
cy.visit("/new-resume");
cy.findByLabelText("Company").type("Git Corp");
cy.findByLabelText("Job").type("Developer");
cy.findByRole("button", { name: "Submit" }).click();

cy.url().should("include", "/resume/git-corp-developer");

cy.getContentGitLog().then((log) => {
expect(log).to.include("Add new resume: git-corp-developer");
});
});

it("should create git commit when updating a resume", function () {
// First create a resume
cy.visit("/new-resume");
cy.findByLabelText("Company").type("Update Corp");
cy.findByLabelText("Job").type("Engineer");
cy.findByRole("button", { name: "Submit" }).click();

// Then update it
cy.findByRole("link", { name: "Edit" }).click();
cy.findByLabelText("Company").clear();
cy.findByLabelText("Company").type("Updated Corp");
cy.findByRole("button", { name: "Submit" }).click();

cy.findByText("Updated Corp");

cy.getContentGitLog().then((log) => {
expect(log).to.include("Update resume: updated-corp-engineer");
});
});

it("should create git commit when deleting a resume", function () {
// First create a resume
cy.visit("/new-resume");
cy.findByLabelText("Company").type("Delete Corp");
cy.findByLabelText("Job").type("Manager");
cy.findByRole("button", { name: "Submit" }).click();

// Then delete it
cy.findByRole("button", { name: "Delete" }).click();

// Should redirect to homepage
cy.url().should("eq", Cypress.config().baseUrl + "/");

cy.getContentGitLog().then((log) => {
expect(log).to.include("Delete resume: delete-corp-manager");
});
});

it("should accumulate commits for multiple operations", function () {
// Create first resume
cy.visit("/new-resume");
cy.findByLabelText("Company").type("First Corp");
cy.findByLabelText("Job").type("Developer");
cy.findByRole("button", { name: "Submit" }).click();

// Create second resume
cy.visit("/new-resume");
cy.findByLabelText("Company").type("Second Corp");
cy.findByLabelText("Job").type("Designer");
cy.findByRole("button", { name: "Submit" }).click();

// Update first resume
cy.visit("/resume/first-corp-developer/edit");
cy.findByLabelText("Job").clear();
cy.findByLabelText("Job").type("Senior Developer");
cy.findByRole("button", { name: "Submit" }).click();

cy.getContentGitLog().then((log) => {
expect(log).to.include("Add new resume: first-corp-developer");
expect(log).to.include("Add new resume: second-corp-designer");
expect(log).to.include("Update resume: first-corp-senior-developer");
});
});
});
Loading