diff --git a/apps/app/src/paths/FolderContext.cy.tsx b/apps/app/src/paths/FolderContext.cy.tsx new file mode 100644 index 000000000..6eee8c15b --- /dev/null +++ b/apps/app/src/paths/FolderContext.cy.tsx @@ -0,0 +1,225 @@ +import { FolderContext } from "./FolderContext"; +import { createMemoryRouter, Outlet, RouterProvider } from "react-router"; +import { SiteContext } from "./SiteHeader"; + +const TEST_USER_ID = "user-abc-123"; + +const mockContext: SiteContext = { + user: { + userId: TEST_USER_ID, + firstNames: "Test", + lastNames: "User", + isAnonymous: false, + email: null, + }, + exploreTab: null, + setExploreTab: () => {}, + addTo: null, + setAddTo: () => {}, + allLicenses: [], + allDoenetmlVersions: [], +}; + +/** Wraps FolderContext with a parent that supplies outlet context and a minimal child route. */ +function mountFolderContext(initialPath: string) { + function TestParent() { + return ; + } + + const router = createMemoryRouter( + [ + { + element: , + children: [ + { + element: , + children: [ + { + path: `/activities/${TEST_USER_ID}`, + element: ( +
Activities Content
+ ), + }, + { + path: "/trash", + element:
Trash Content
, + }, + { + path: `/sharedWithMe/${TEST_USER_ID}`, + element:
Shared Content
, + }, + ], + }, + ], + }, + ], + { initialEntries: [initialPath] }, + ); + + cy.mount(); +} + +describe("FolderContext navigation panel", { tags: ["@group1"] }, () => { + describe("navigation link rendering", () => { + it("renders all three navigation links", () => { + mountFolderContext(`/activities/${TEST_USER_ID}`); + cy.get('[data-test="My Activities Link"]').should("be.visible"); + cy.get('[data-test="Shared With Me Button"]').should("be.visible"); + cy.get('[data-test="Trash Link"]').should("be.visible"); + }); + + it("renders the outlet content", () => { + mountFolderContext(`/activities/${TEST_USER_ID}`); + cy.get('[data-test="outlet-content"]').should( + "contain.text", + "Activities Content", + ); + }); + }); + + describe("active tab marking (aria-current)", () => { + it("marks My Activities as current when on activities path", () => { + mountFolderContext(`/activities/${TEST_USER_ID}`); + cy.get('[data-test="My Activities Link"]').should( + "have.attr", + "aria-current", + "page", + ); + cy.get('[data-test="Shared With Me Button"]').should( + "not.have.attr", + "aria-current", + ); + cy.get('[data-test="Trash Link"]').should( + "not.have.attr", + "aria-current", + ); + }); + + it("marks Trash as current when on trash path", () => { + mountFolderContext("/trash"); + cy.get('[data-test="Trash Link"]').should( + "have.attr", + "aria-current", + "page", + ); + cy.get('[data-test="My Activities Link"]').should( + "not.have.attr", + "aria-current", + ); + cy.get('[data-test="Shared With Me Button"]').should( + "not.have.attr", + "aria-current", + ); + }); + + it("marks Shared With Me as current when on sharedWithMe path", () => { + mountFolderContext(`/sharedWithMe/${TEST_USER_ID}`); + cy.get('[data-test="Shared With Me Button"]').should( + "have.attr", + "aria-current", + "page", + ); + cy.get('[data-test="My Activities Link"]').should( + "not.have.attr", + "aria-current", + ); + cy.get('[data-test="Trash Link"]').should( + "not.have.attr", + "aria-current", + ); + }); + }); + + describe("small screen: de-emphasize inactive tabs", () => { + beforeEach(() => { + cy.viewport(375, 667); // small/mobile screen + }); + + it("active My Activities tab has full opacity; inactive tabs are de-emphasized", () => { + mountFolderContext(`/activities/${TEST_USER_ID}`); + cy.get('[data-test="My Activities Link"]').should( + "have.css", + "opacity", + "1", + ); + cy.get('[data-test="Trash Link"]').should("have.css", "opacity", "0.5"); + cy.get('[data-test="Shared With Me Button"]').should( + "have.css", + "opacity", + "0.5", + ); + }); + + it("active Trash tab has full opacity; inactive tabs are de-emphasized", () => { + mountFolderContext("/trash"); + cy.get('[data-test="Trash Link"]').should("have.css", "opacity", "1"); + cy.get('[data-test="My Activities Link"]').should( + "have.css", + "opacity", + "0.5", + ); + cy.get('[data-test="Shared With Me Button"]').should( + "have.css", + "opacity", + "0.5", + ); + }); + + it("active Shared With Me tab has full opacity; inactive tabs are de-emphasized", () => { + mountFolderContext(`/sharedWithMe/${TEST_USER_ID}`); + cy.get('[data-test="Shared With Me Button"]').should( + "have.css", + "opacity", + "1", + ); + cy.get('[data-test="My Activities Link"]').should( + "have.css", + "opacity", + "0.5", + ); + cy.get('[data-test="Trash Link"]').should("have.css", "opacity", "0.5"); + }); + }); + + describe("medium screen: all tabs have full opacity", () => { + beforeEach(() => { + cy.viewport(1024, 768); // medium screen (above md breakpoint) + }); + + it("all tabs have full opacity regardless of active state", () => { + mountFolderContext(`/activities/${TEST_USER_ID}`); + cy.get('[data-test="My Activities Link"]').should( + "have.css", + "opacity", + "1", + ); + cy.get('[data-test="Trash Link"]').should("have.css", "opacity", "1"); + cy.get('[data-test="Shared With Me Button"]').should( + "have.css", + "opacity", + "1", + ); + }); + }); + + describe("accessibility", () => { + it("passes accessibility on My Activities page", () => { + mountFolderContext(`/activities/${TEST_USER_ID}`); + cy.wait(100); + cy.checkAccessibility("body"); + }); + + it("passes accessibility on Trash page", () => { + mountFolderContext("/trash"); + cy.wait(100); + cy.checkAccessibility("body"); + }); + + it("passes accessibility on small screens", () => { + cy.viewport(375, 667); + mountFolderContext(`/activities/${TEST_USER_ID}`); + cy.wait(100); + cy.checkAccessibility("body"); + }); + }); +}); diff --git a/apps/app/src/paths/FolderContext.tsx b/apps/app/src/paths/FolderContext.tsx index 5b4f21fcd..6ec8ad05a 100644 --- a/apps/app/src/paths/FolderContext.tsx +++ b/apps/app/src/paths/FolderContext.tsx @@ -22,6 +22,7 @@ export function FolderContext() { flexShrink={0} align="flex-start" borderRight={{ base: "none", md: "solid 2px black" }} + borderBottom={{ base: "solid 2px black", md: "none" }} p={{ base: "0px", xl: "10px" }} minHeight={{ base: "fit-content", md: "100%" }} flexDir={{ base: "row", md: "column" }} @@ -31,7 +32,10 @@ export function FolderContext() { to={activitiesPath} variant="ghost" justifyContent="flex-start" - width={isActivitiesActive ? "100%" : "calc(100% - 4px)"} + width={{ + base: "auto", + md: isActivitiesActive ? "100%" : "calc(100% - 4px)", + }} backgroundColor={ isActivitiesActive ? "doenet.lightBlue" : "transparent" } @@ -40,9 +44,14 @@ export function FolderContext() { ? { backgroundColor: "doenet.lightBlue" } : { backgroundColor: "gray.50" } } - borderLeftWidth={isActivitiesActive ? "4px" : "0"} - marginLeft={isActivitiesActive ? "0" : "4px"} + borderLeftWidth={{ base: "0", md: isActivitiesActive ? "4px" : "0" }} + marginLeft={{ base: "0", md: isActivitiesActive ? "0" : "4px" }} borderLeftColor={isActivitiesActive ? "doenet.mainBlue" : "transparent"} + borderBottomWidth={{ base: isActivitiesActive ? "3px" : "0", md: "0" }} + borderBottomColor={ + isActivitiesActive ? "doenet.mainBlue" : "transparent" + } + opacity={{ base: isActivitiesActive ? 1 : 0.5, md: 1 }} aria-current={isActivitiesActive ? "page" : undefined} data-test="My Activities Link" > @@ -54,7 +63,10 @@ export function FolderContext() { to={`/sharedWithMe/${context.user?.userId ?? ""}`} variant="ghost" justifyContent="flex-start" - width={isSharedWithMeActive ? "100%" : "calc(100% - 4px)"} + width={{ + base: "auto", + md: isSharedWithMeActive ? "100%" : "calc(100% - 4px)", + }} backgroundColor={ isSharedWithMeActive ? "doenet.lightBlue" : "transparent" } @@ -63,11 +75,19 @@ export function FolderContext() { ? { backgroundColor: "doenet.lightBlue" } : { backgroundColor: "gray.50" } } - borderLeftWidth={isSharedWithMeActive ? "4px" : "0"} - marginLeft={isSharedWithMeActive ? "0" : "4px"} + borderLeftWidth={{ base: "0", md: isSharedWithMeActive ? "4px" : "0" }} + marginLeft={{ base: "0", md: isSharedWithMeActive ? "0" : "4px" }} borderLeftColor={ isSharedWithMeActive ? "doenet.mainBlue" : "transparent" } + borderBottomWidth={{ + base: isSharedWithMeActive ? "3px" : "0", + md: "0", + }} + borderBottomColor={ + isSharedWithMeActive ? "doenet.mainBlue" : "transparent" + } + opacity={{ base: isSharedWithMeActive ? 1 : 0.5, md: 1 }} aria-current={isSharedWithMeActive ? "page" : undefined} data-test="Shared With Me Button" > @@ -82,16 +102,22 @@ export function FolderContext() { to={`/trash`} variant="ghost" justifyContent="flex-start" - width={isTrashActive ? "100%" : "calc(100% - 4px)"} + width={{ + base: "auto", + md: isTrashActive ? "100%" : "calc(100% - 4px)", + }} backgroundColor={isTrashActive ? "doenet.lightBlue" : "transparent"} _hover={ isTrashActive ? { backgroundColor: "doenet.lightBlue" } : { backgroundColor: "gray.50" } } - borderLeftWidth={isTrashActive ? "4px" : "0"} - marginLeft={isTrashActive ? "0" : "4px"} + borderLeftWidth={{ base: "0", md: isTrashActive ? "4px" : "0" }} + marginLeft={{ base: "0", md: isTrashActive ? "0" : "4px" }} borderLeftColor={isTrashActive ? "doenet.mainBlue" : "transparent"} + borderBottomWidth={{ base: isTrashActive ? "3px" : "0", md: "0" }} + borderBottomColor={isTrashActive ? "doenet.mainBlue" : "transparent"} + opacity={{ base: isTrashActive ? 1 : 0.5, md: 1 }} aria-current={isTrashActive ? "page" : undefined} data-test="Trash Link" > diff --git a/package-lock.json b/package-lock.json index 6165508f7..1817d9afa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4352,9 +4352,6 @@ "cpu": [ "arm" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4368,9 +4365,6 @@ "cpu": [ "arm" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4384,9 +4378,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4400,9 +4391,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4416,9 +4404,6 @@ "cpu": [ "loong64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4432,9 +4417,6 @@ "cpu": [ "loong64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4448,9 +4430,6 @@ "cpu": [ "ppc64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4464,9 +4443,6 @@ "cpu": [ "ppc64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4480,9 +4456,6 @@ "cpu": [ "riscv64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4496,9 +4469,6 @@ "cpu": [ "riscv64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4512,9 +4482,6 @@ "cpu": [ "s390x" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4528,9 +4495,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4544,9 +4508,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [