2026-02-08 16:07:06 +00:00
|
|
|
describe("Organizations (PR #61)", () => {
|
|
|
|
|
const email = Cypress.env("CLERK_TEST_EMAIL") || "jane+clerk_test@example.com";
|
|
|
|
|
|
2026-02-08 16:21:51 +00:00
|
|
|
it("negative: signed-out user is redirected to sign-in when opening /organization", () => {
|
|
|
|
|
cy.visit("/organization");
|
|
|
|
|
cy.location("pathname", { timeout: 30_000 }).should("match", /\/sign-in/);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("positive: org owner can create an org and invite a member (copy invite link)", () => {
|
|
|
|
|
// Story (positive): user signs in, creates a new org, then invites a teammate.
|
2026-02-08 16:07:06 +00:00
|
|
|
cy.visit("/sign-in");
|
|
|
|
|
cy.clerkLoaded();
|
|
|
|
|
cy.clerkSignIn({ strategy: "email_code", identifier: email });
|
|
|
|
|
|
2026-02-08 16:21:51 +00:00
|
|
|
// Go to a page that shows OrgSwitcher.
|
|
|
|
|
cy.visit("/boards");
|
|
|
|
|
|
|
|
|
|
// Create a new org via OrgSwitcher.
|
2026-02-08 16:36:56 +00:00
|
|
|
// The switcher is a Shadcn Select trigger (`role=combobox`).
|
|
|
|
|
cy.get('button[role="combobox"]', { timeout: 30_000 })
|
|
|
|
|
.first()
|
2026-02-08 16:21:51 +00:00
|
|
|
.should("be.visible")
|
|
|
|
|
.click();
|
|
|
|
|
|
2026-02-08 16:36:56 +00:00
|
|
|
cy.contains(/create new org/i, { timeout: 30_000 }).should("be.visible").click();
|
2026-02-08 16:07:06 +00:00
|
|
|
|
2026-02-08 16:21:51 +00:00
|
|
|
const orgName = `Cypress Org ${Date.now()}`;
|
|
|
|
|
cy.get("#org-name").should("be.visible").clear().type(orgName);
|
|
|
|
|
cy.contains("button", /^create org$/i).should("be.visible").click();
|
|
|
|
|
|
|
|
|
|
// Creating org triggers a reload; ensure we land back in the app.
|
|
|
|
|
cy.location("pathname", { timeout: 60_000 }).should("match", /\/(boards|organization|activity)/);
|
|
|
|
|
|
|
|
|
|
// Now visit organization admin page and create an invite.
|
|
|
|
|
cy.visit("/organization");
|
2026-02-08 16:07:06 +00:00
|
|
|
cy.contains(/members\s*&\s*invites/i, { timeout: 30_000 }).should("be.visible");
|
|
|
|
|
|
2026-02-08 16:21:51 +00:00
|
|
|
cy.contains("button", /invite member/i).should("be.visible").click();
|
|
|
|
|
|
|
|
|
|
const invitedEmail = `cypress+invite-${Date.now()}@example.com`;
|
|
|
|
|
cy.get('input[type="email"]').should("be.visible").clear().type(invitedEmail);
|
|
|
|
|
|
|
|
|
|
// Invite submit button text varies; match loosely.
|
|
|
|
|
cy.contains("button", /invite/i).should("be.visible").click();
|
|
|
|
|
|
|
|
|
|
// Confirm invite shows up in table.
|
|
|
|
|
cy.contains(invitedEmail, { timeout: 30_000 }).should("be.visible");
|
|
|
|
|
|
|
|
|
|
// Stub clipboard and verify "Copy link" emits /invite?token=...
|
|
|
|
|
cy.window().then((win) => {
|
|
|
|
|
if (!win.navigator.clipboard) {
|
|
|
|
|
// @ts-expect-error - allow defining clipboard in test runtime
|
|
|
|
|
win.navigator.clipboard = { writeText: () => Promise.resolve() };
|
|
|
|
|
}
|
|
|
|
|
cy.stub(win.navigator.clipboard, "writeText").as("writeText");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
cy.contains("tr", invitedEmail)
|
2026-02-08 16:07:06 +00:00
|
|
|
.should("be.visible")
|
2026-02-08 16:21:51 +00:00
|
|
|
.within(() => {
|
|
|
|
|
cy.contains("button", /copy link/i).click();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
cy.get("@writeText").should("have.been.calledOnce");
|
|
|
|
|
cy.get("@writeText").should((writeText) => {
|
|
|
|
|
const stub = writeText as unknown as sinon.SinonStub;
|
|
|
|
|
const text = stub.getCall(0).args[0] as string;
|
|
|
|
|
expect(text).to.match(/\/invite\?token=/);
|
|
|
|
|
});
|
2026-02-08 16:07:06 +00:00
|
|
|
});
|
|
|
|
|
});
|