@@ -66,7 +73,15 @@
:session-id="selectedSessionId"
:session-label="selectedSessionLabel"
@close="toggleEditSessionLabelOpen(false)"
+ @confirm="deleteSession"
>
+
@@ -83,6 +98,7 @@ import userMessages from "../../userMessages";
import ErrorsAlert from "../ErrorsAlert.vue";
import EditSessionLabel from "./EditSessionLabel.vue";
import { SessionMetadata } from "../../types/responseTypes";
+import ConfirmModal from "../ConfirmModal.vue";
export default defineComponent({
name: "SessionsPage",
@@ -90,10 +106,12 @@ export default defineComponent({
ErrorsAlert,
EditSessionLabel,
VueFeather,
- RouterLink
+ RouterLink,
+ ConfirmModal
},
setup() {
const store = useStore();
+ const namespace = "sessions";
const sessionsMetadata = computed(() => store.state.sessions.sessionsMetadata);
const baseUrl = computed(() => store.state.baseUrl);
@@ -108,6 +126,8 @@ export default defineComponent({
const lastCopySessionId = ref
(null);
const lastCopyMsg = ref(null); // Feedback message to show under last copy control clicked
+ const sessionIdToDelete = ref("");
+
const formatDateTime = (isoUTCString: string) => {
return utc(isoUTCString).local().format("DD/MM/YYYY HH:mm:ss");
};
@@ -133,7 +153,7 @@ export default defineComponent({
return session.friendlyId;
}
lastCopyMsg.value = "Fetching code...";
- await store.dispatch(`sessions/${SessionsAction.GenerateFriendlyId}`, session.id);
+ await store.dispatch(`${namespace}/${SessionsAction.GenerateFriendlyId}`, session.id);
await nextTick();
const friendlyId = sessionsMetadata.value.find((m: SessionMetadata) => m.id === session.id)?.friendlyId;
if (!friendlyId) {
@@ -171,8 +191,21 @@ export default defineComponent({
lastCopyMsg.value = null;
};
+ const confirmDeleteSessionOpen = ref(false);
+ const toggleConfirmDeleteSessionOpen = (open: boolean) => {
+ confirmDeleteSessionOpen.value = open;
+ };
+ const confirmDeleteSession = (sessionId: string) => {
+ sessionIdToDelete.value = sessionId;
+ toggleConfirmDeleteSessionOpen(true);
+ };
+
+ const deleteSession = () => {
+ store.dispatch(`${namespace}/${SessionsAction.DeleteSession}`, sessionIdToDelete.value);
+ };
+
onMounted(() => {
- store.dispatch(`sessions/${SessionsAction.GetSessions}`);
+ store.dispatch(`${namespace}/${SessionsAction.GetSessions}`);
});
const messages = userMessages.sessions;
@@ -187,12 +220,16 @@ export default defineComponent({
selectedSessionLabel,
lastCopySessionId,
lastCopyMsg,
+ confirmDeleteSessionOpen,
editSessionLabel,
toggleEditSessionLabelOpen,
copyLink,
copyCode,
getCopyMsg,
clearLastCopied,
+ confirmDeleteSession,
+ toggleConfirmDeleteSessionOpen,
+ deleteSession,
messages
};
}
diff --git a/app/static/src/app/localStorageManager.ts b/app/static/src/app/localStorageManager.ts
index 9d4dc5172..a36fbc82f 100644
--- a/app/static/src/app/localStorageManager.ts
+++ b/app/static/src/app/localStorageManager.ts
@@ -9,10 +9,20 @@ class LocalStorageManager {
return (serialised ? JSON.parse(serialised) : []) as string[];
}
+ saveSessionIds = (appName: string, basePath: string, sessionIds: string[]) => {
+ window.localStorage.setItem(LocalStorageManager._sessionIdsKey(appName, basePath), JSON.stringify(sessionIds));
+ }
+
addSessionId = (appName: string, basePath: string, sessionId: string) => {
const sessionIds = this.getSessionIds(appName, basePath);
sessionIds.unshift(sessionId); // prepends the id
- window.localStorage.setItem(LocalStorageManager._sessionIdsKey(appName, basePath), JSON.stringify(sessionIds));
+ this.saveSessionIds(appName, basePath, sessionIds);
+ }
+
+ deleteSessionId = (appName: string, basePath: string, sessionId: string) => {
+ let sessionIds = this.getSessionIds(appName, basePath);
+ sessionIds = sessionIds.filter((s) => s !== sessionId);
+ this.saveSessionIds(appName, basePath, sessionIds);
}
}
diff --git a/app/static/src/app/store/sessions/actions.ts b/app/static/src/app/store/sessions/actions.ts
index 45bb10a90..06651f216 100644
--- a/app/static/src/app/store/sessions/actions.ts
+++ b/app/static/src/app/store/sessions/actions.ts
@@ -17,7 +17,8 @@ export enum SessionsAction {
GetSessions = "GetSessions",
Rehydrate = "Rehydrate",
SaveSessionLabel = "SaveSessionLabel",
- GenerateFriendlyId = "GenerateFriendlyId"
+ GenerateFriendlyId = "GenerateFriendlyId",
+ DeleteSession = "DeleteSession"
}
interface SaveSessionLabelPayload {
@@ -99,5 +100,12 @@ export const actions: ActionTree = {
if (response) {
commit(SessionsMutation.SetSessionFriendlyId, { sessionId, friendlyId: response.data });
}
+ },
+
+ async [SessionsAction.DeleteSession](context, sessionId: string) {
+ const { rootState, rootGetters, commit } = context;
+ const { appName } = rootState;
+ localStorageManager.deleteSessionId(appName!, rootGetters[AppStateGetter.baseUrlPath], sessionId);
+ commit(SessionsMutation.RemoveSessionId, sessionId);
}
};
diff --git a/app/static/src/app/store/sessions/mutations.ts b/app/static/src/app/store/sessions/mutations.ts
index bff01501f..ac660594d 100644
--- a/app/static/src/app/store/sessions/mutations.ts
+++ b/app/static/src/app/store/sessions/mutations.ts
@@ -4,7 +4,8 @@ import { SessionMetadata } from "../../types/responseTypes";
export enum SessionsMutation {
SetSessionsMetadata = "SetSessionsMetadata",
- SetSessionFriendlyId = "SetSessionFriendlyId"
+ SetSessionFriendlyId = "SetSessionFriendlyId",
+ RemoveSessionId = "RemoveSessionId"
}
export interface SetSessionFriendlyIdPayload {
@@ -22,5 +23,11 @@ export const mutations: MutationTree = {
if (sessionMetadata) {
sessionMetadata.friendlyId = payload.friendlyId;
}
+ },
+
+ [SessionsMutation.RemoveSessionId](state: SessionsState, payload: string) {
+ if (state.sessionsMetadata) {
+ state.sessionsMetadata = state.sessionsMetadata.filter((s) => s.id !== payload);
+ }
}
};
diff --git a/app/static/tests/e2e/sessions.etest.ts b/app/static/tests/e2e/sessions.etest.ts
index 7bcbf4203..e4a9631c9 100644
--- a/app/static/tests/e2e/sessions.etest.ts
+++ b/app/static/tests/e2e/sessions.etest.ts
@@ -23,7 +23,7 @@ const enterSessionLabel = async (page: Page, dialogId: string, newLabel: string)
test.describe("Sessions tests", () => {
const { timeout } = PlaywrightConfig;
- test("can navigate to Sessions page from navbar, and load a session", async () => {
+ test("can use Sessions page", async () => {
// We need to use a browser with persistent context instead of the default incognito browser so that
// we can use the session ids in local storage
const userDataDir = os.tmpdir();
@@ -83,7 +83,8 @@ test.describe("Sessions tests", () => {
await expect(await page.innerText(":nth-match(.session-col-header, 2)")).toBe("Label");
await expect(await page.innerText(":nth-match(.session-col-header, 3)")).toBe("Edit Label");
await expect(await page.innerText(":nth-match(.session-col-header, 4)")).toBe("Load");
- await expect(await page.innerText(":nth-match(.session-col-header, 5)")).toBe("Shareable Link");
+ await expect(await page.innerText(":nth-match(.session-col-header, 5)")).toBe("Delete");
+ await expect(await page.innerText(":nth-match(.session-col-header, 6)")).toBe("Shareable Link");
await expect(await page.innerText(".session-label")).toBe("--no label--");
@@ -185,6 +186,18 @@ test.describe("Sessions tests", () => {
await page.goto(copiedLinkText);
await expect(await page.innerText("#data-upload-success")).toBe(" Uploaded 32 rows and 2 columns");
+ // can delete session
+ await page.goto(`${appUrl}/sessions`);
+ await expect(await page.locator("#app .container .row").count()).toBeGreaterThan(3);
+ await page.locator(":nth-match(#app .container .row, 4) .session-edit-label i").click();
+ await enterSessionLabel(page, "page-edit-session-label", "delete me");
+
+ await expect(await page.locator(".row:has-text('delete me')")).toBeVisible({ timeout });
+ await page.locator(".row:has-text('delete me') .session-delete i").click();
+ await expect(await page.locator("#confirm-yes")).toBeVisible();
+ await page.click("#confirm-yes");
+ await expect(await page.locator("#app")).not.toContainText("delete me");
+
await browser.close();
});
});
diff --git a/app/static/tests/unit/components/confirmModal.test.ts b/app/static/tests/unit/components/confirmModal.test.ts
new file mode 100644
index 000000000..6d61bd203
--- /dev/null
+++ b/app/static/tests/unit/components/confirmModal.test.ts
@@ -0,0 +1,36 @@
+import { mount } from "@vue/test-utils";
+import ConfirmModal from "../../../src/app/components/ConfirmModal.vue";
+
+describe("ConfirmModal", () => {
+ const getWrapper = (open = true, title = "Delete something", text = "Really?") => {
+ return mount(ConfirmModal, { props: { title, text, open } });
+ };
+
+ it("renders as expected", () => {
+ const wrapper = getWrapper();
+ expect(wrapper.find(".modal-title").text()).toBe("Delete something");
+ expect(wrapper.find(".modal-body").text()).toBe("Really?");
+ expect(wrapper.find("button#confirm-yes").text()).toBe("Yes");
+ expect(wrapper.find("button#confirm-no").text()).toBe("No");
+ expect((wrapper.find("div.modal").element as HTMLDivElement).style.display).toBe("block");
+ });
+
+ it("hides modal when not open", () => {
+ const wrapper = getWrapper(false);
+ expect((wrapper.find("div.modal").element as HTMLDivElement).style.display).toBe("none");
+ });
+
+ it("No button emits close", async () => {
+ const wrapper = getWrapper();
+ await wrapper.find("button#confirm-no").trigger("click");
+ expect(wrapper.emitted("close")!.length).toBe(1);
+ expect(wrapper.emitted("confirm")).toBe(undefined);
+ });
+
+ it("Yes button emits close and confirm", async () => {
+ const wrapper = getWrapper();
+ await wrapper.find("button#confirm-yes").trigger("click");
+ expect(wrapper.emitted("close")!.length).toBe(1);
+ expect(wrapper.emitted("confirm")!.length).toBe(1);
+ });
+});
diff --git a/app/static/tests/unit/components/sessions/sessionsPage.test.ts b/app/static/tests/unit/components/sessions/sessionsPage.test.ts
index 75cbcc4ba..b08af336a 100644
--- a/app/static/tests/unit/components/sessions/sessionsPage.test.ts
+++ b/app/static/tests/unit/components/sessions/sessionsPage.test.ts
@@ -9,11 +9,13 @@ import { mockBasicState } from "../../../mocks";
import { SessionsAction } from "../../../../src/app/store/sessions/actions";
import { SessionMetadata } from "../../../../src/app/types/responseTypes";
import EditSessionLabel from "../../../../src/app/components/sessions/EditSessionLabel.vue";
+import ConfirmModal from "../../../../src/app/components/ConfirmModal.vue";
describe("SessionsPage", () => {
const mockGetSessions = jest.fn();
const mockGenerateFriendlyId = jest.fn();
const mockClipboardWriteText = jest.fn();
+ const mockDeleteSession = jest.fn();
Object.assign(window.navigator, {
clipboard: {
@@ -41,7 +43,8 @@ describe("SessionsPage", () => {
},
actions: {
[SessionsAction.GetSessions]: mockGetSessions,
- [SessionsAction.GenerateFriendlyId]: mockGenerateFriendlyId
+ [SessionsAction.GenerateFriendlyId]: mockGenerateFriendlyId,
+ [SessionsAction.DeleteSession]: mockDeleteSession
}
}
}
@@ -70,38 +73,42 @@ describe("SessionsPage", () => {
const rows = wrapper.findAll(".container .row");
expect(rows.at(0)!.find("h2").text()).toBe("Sessions");
const columnHeaders = rows.at(1)!.findAll("div.session-col-header");
- expect(columnHeaders.length).toBe(5);
+ expect(columnHeaders.length).toBe(6);
expect(columnHeaders.at(0)!.text()).toBe("Saved");
expect(columnHeaders.at(1)!.text()).toBe("Label");
expect(columnHeaders.at(2)!.text()).toBe("Edit Label");
expect(columnHeaders.at(3)!.text()).toBe("Load");
- expect(columnHeaders.at(4)!.text()).toBe("Shareable Link");
+ expect(columnHeaders.at(4)!.text()).toBe("Delete");
+ expect(columnHeaders.at(5)!.text()).toBe("Shareable Link");
const session1Cells = rows.at(2)!.findAll("div.session-col-value");
- expect(session1Cells.length).toBe(5);
+ expect(session1Cells.length).toBe(6);
expect(session1Cells.at(0)!.text()).toBe("13/01/2022 09:26:36 (current session)");
expect(session1Cells.at(1)!.text()).toBe("session1");
expect(session1Cells.at(2)!.findComponent(VueFeather).props("type")).toBe("edit-2");
const routerLink = session1Cells.at(3)!.findComponent(RouterLink);
expect(routerLink.props("to")).toBe("/");
- expect(session1Cells.at(4)!.find("span.session-copy-link").text()).toBe("Copy link");
- expect(session1Cells.at(4)!.find("span.session-copy-link").findComponent(VueFeather).props("type"))
+ // No delete control for current session
+ expect(session1Cells.at(4)!.findComponent(VueFeather).exists()).toBe(false);
+ expect(session1Cells.at(5)!.find("span.session-copy-link").text()).toBe("Copy link");
+ expect(session1Cells.at(5)!.find("span.session-copy-link").findComponent(VueFeather).props("type"))
.toBe("copy");
- expect(session1Cells.at(4)!.find("span.session-copy-code").text()).toBe("Copy code");
- expect(session1Cells.at(4)!.find("span.session-copy-code").findComponent(VueFeather).props("type"))
+ expect(session1Cells.at(5)!.find("span.session-copy-code").text()).toBe("Copy code");
+ expect(session1Cells.at(5)!.find("span.session-copy-code").findComponent(VueFeather).props("type"))
.toBe("copy");
- expect(session1Cells.at(4)!.find(".session-copy-confirm").text()).toBe("");
+ expect(session1Cells.at(5)!.find(".session-copy-confirm").text()).toBe("");
const session2Cells = rows.at(3)!.findAll("div.session-col-value");
- expect(session1Cells.length).toBe(5);
+ expect(session1Cells.length).toBe(6);
expect(session2Cells.at(0)!.text()).toBe("13/01/2022 10:26:36");
expect(session2Cells.at(1)!.text()).toBe("--no label--");
expect(session2Cells.at(2)!.findComponent(VueFeather).props("type")).toBe("edit-2");
expect(session2Cells.at(3)!.find("a").attributes("href"))
.toBe("http://localhost:3000/apps/testApp/?sessionId=def");
expect(session2Cells.at(3)!.find("a").findComponent(VueFeather).props("type")).toBe("upload");
- expect(session2Cells.at(4)!.find("span.session-copy-link").text()).toBe("Copy link");
- expect(session2Cells.at(4)!.find("span.session-copy-code").text()).toBe("Copy code");
- expect(session2Cells.at(4)!.find(".session-copy-confirm").text()).toBe("");
+ expect(session2Cells.at(4)!.findComponent(VueFeather).props("type")).toBe("trash-2");
+ expect(session2Cells.at(5)!.find("span.session-copy-link").text()).toBe("Copy link");
+ expect(session2Cells.at(5)!.find("span.session-copy-code").text()).toBe("Copy code");
+ expect(session2Cells.at(5)!.find(".session-copy-confirm").text()).toBe("");
const editDlg = wrapper.findComponent(EditSessionLabel);
expect(editDlg.props("open")).toBe(false);
@@ -109,6 +116,9 @@ describe("SessionsPage", () => {
expect(editDlg.props("sessionLabel")).toBe(null);
expect(wrapper.findComponent(ErrorsAlert).exists()).toBe(true);
+ expect(wrapper.findComponent(ConfirmModal).props("open")).toBe(false);
+ expect(wrapper.findComponent(ConfirmModal).props("title")).toBe("Delete session");
+ expect(wrapper.findComponent(ConfirmModal).props("text")).toBe("Do you want to delete this session?");
});
it("shows loading message when session metadata is null in store", () => {
@@ -149,11 +159,11 @@ describe("SessionsPage", () => {
const rows = wrapper.findAll(".container .row");
// session 1 already has a friendly id so action should not be dispatched
const session1Cells = rows.at(2)!.findAll("div.session-col-value");
- await session1Cells.at(4)!.find(".session-copy-link").trigger("click");
+ await session1Cells.at(5)!.find(".session-copy-link").trigger("click");
expect(mockGenerateFriendlyId).not.toHaveBeenCalled();
// session 2 has no friendly id so action should be dispatched
const session2Cells = rows.at(3)!.findAll("div.session-col-value");
- await session2Cells.at(4)!.find(".session-copy-link").trigger("click");
+ await session2Cells.at(5)!.find(".session-copy-link").trigger("click");
expect(mockGenerateFriendlyId).toHaveBeenCalledTimes(1);
expect(mockGenerateFriendlyId.mock.calls[0][1]).toBe("def");
});
@@ -163,11 +173,11 @@ describe("SessionsPage", () => {
const rows = wrapper.findAll(".container .row");
// session 1 already has a friendly id so action should not be dispatched
const session1Cells = rows.at(2)!.findAll("div.session-col-value");
- await session1Cells.at(4)!.find(".session-copy-code").trigger("click");
+ await session1Cells.at(5)!.find(".session-copy-code").trigger("click");
expect(mockGenerateFriendlyId).not.toHaveBeenCalled();
// session 2 has no friendly id so action should be dispatched
const session2Cells = rows.at(3)!.findAll("div.session-col-value");
- await session2Cells.at(4)!.find(".session-copy-code").trigger("click");
+ await session2Cells.at(5)!.find(".session-copy-code").trigger("click");
expect(mockGenerateFriendlyId).toHaveBeenCalledTimes(1);
expect(mockGenerateFriendlyId.mock.calls[0][1]).toBe("def");
});
@@ -176,14 +186,14 @@ describe("SessionsPage", () => {
const wrapper = getWrapper(sessionsMetadata);
const rows = wrapper.findAll(".container .row");
const session1Cells = rows.at(2)!.findAll("div.session-col-value");
- await session1Cells.at(4)!.find(".session-copy-link").trigger("click");
+ await session1Cells.at(5)!.find(".session-copy-link").trigger("click");
const expectedLink = "http://localhost:3000/apps/testApp/?share=bad-cat";
expect(mockClipboardWriteText).toHaveBeenCalledTimes(1);
expect(mockClipboardWriteText.mock.calls[0][0]).toBe(expectedLink);
- expect(session1Cells.at(4)!.find(".session-copy-confirm").text())
+ expect(session1Cells.at(5)!.find(".session-copy-confirm").text())
.toBe(`Copied: ${expectedLink}`);
});
@@ -191,12 +201,12 @@ describe("SessionsPage", () => {
const wrapper = getWrapper(sessionsMetadata);
const rows = wrapper.findAll(".container .row");
const session1Cells = rows.at(2)!.findAll("div.session-col-value");
- await session1Cells.at(4)!.find(".session-copy-code").trigger("click");
+ await session1Cells.at(5)!.find(".session-copy-code").trigger("click");
expect(mockClipboardWriteText).toHaveBeenCalledTimes(1);
expect(mockClipboardWriteText.mock.calls[0][0]).toBe("bad-cat");
- expect(session1Cells.at(4)!.find(".session-copy-confirm").text())
+ expect(session1Cells.at(5)!.find(".session-copy-confirm").text())
.toBe("Copied: bad-cat");
});
@@ -204,11 +214,11 @@ describe("SessionsPage", () => {
const wrapper = getWrapper(sessionsMetadata);
const rows = wrapper.findAll(".container .row");
const session1Cells = rows.at(2)!.findAll("div.session-col-value");
- await session1Cells.at(4)!.find(".session-copy-code").trigger("click");
- expect(session1Cells.at(4)!.find(".session-copy-confirm").text()).toBe("Copied: bad-cat");
+ await session1Cells.at(5)!.find(".session-copy-code").trigger("click");
+ expect(session1Cells.at(5)!.find(".session-copy-confirm").text()).toBe("Copied: bad-cat");
- await session1Cells.at(4)!.find(".session-copy-code").trigger("mouseleave");
- expect(session1Cells.at(4)!.find(".session-copy-confirm").text()).toBe("");
+ await session1Cells.at(5)!.find(".session-copy-code").trigger("mouseleave");
+ expect(session1Cells.at(5)!.find(".session-copy-confirm").text()).toBe("");
});
it("copy confirmation indicates if friendly id is being fetched, and could not be generated", (done) => {
@@ -218,9 +228,9 @@ describe("SessionsPage", () => {
const wrapper = getWrapper(sessionsMetadata);
const rows = wrapper.findAll(".container .row");
const session2Cells = rows.at(3)!.findAll("div.session-col-value");
- await session2Cells.at(4)!.find(".session-copy-code").trigger("click");
+ await session2Cells.at(5)!.find(".session-copy-code").trigger("click");
// message will update to 'Fetching code...' while it calls the action
- const confirm = session2Cells.at(4)!.find(".session-copy-confirm");
+ const confirm = session2Cells.at(5)!.find(".session-copy-confirm");
expect(confirm.text()).toBe("Fetching code...");
// when action is completed, id has not been successfully updated
@@ -231,4 +241,26 @@ describe("SessionsPage", () => {
};
runAsync();
});
+
+ it("opens and closes confirm delete dialog", async () => {
+ const wrapper = getWrapper(sessionsMetadata);
+ const rows = wrapper.findAll(".container .row");
+ const session1Cells = rows.at(3)!.findAll("div.session-col-value");
+ await session1Cells.at(4)!.findComponent(VueFeather).trigger("click");
+ const confirm = wrapper.findComponent(ConfirmModal);
+ expect(confirm.props("open")).toBe(true);
+ await confirm.vm.$emit("close");
+ expect(confirm.props("open")).toBe(false);
+ });
+
+ it("deletes session on confirm", async () => {
+ const wrapper = getWrapper(sessionsMetadata);
+ const rows = wrapper.findAll(".container .row");
+ const session1Cells = rows.at(3)!.findAll("div.session-col-value");
+ await session1Cells.at(4)!.findComponent(VueFeather).trigger("click"); // set session to delete
+ const confirm = wrapper.findComponent(ConfirmModal);
+ await confirm.vm.$emit("confirm");
+ expect(mockDeleteSession).toHaveBeenCalledTimes(1);
+ expect(mockDeleteSession.mock.calls[0][1]).toBe("def");
+ });
});
diff --git a/app/static/tests/unit/localStorageManager.test.ts b/app/static/tests/unit/localStorageManager.test.ts
index 9da5d2818..906bf20cb 100644
--- a/app/static/tests/unit/localStorageManager.test.ts
+++ b/app/static/tests/unit/localStorageManager.test.ts
@@ -37,4 +37,12 @@ describe("localStorageManager", () => {
expect(spyOnSetItem.mock.calls[0][0]).toBe("testInstance_day1_sessionIds");
expect(spyOnSetItem.mock.calls[0][1]).toBe(JSON.stringify(["session3", "session1", "session2"]));
});
+
+ it("can delete session id", () => {
+ localStorageManager.deleteSessionId("day1", "testInstance", "session2");
+ expect(spyOnGetItem).toHaveBeenCalledTimes(1);
+ expect(spyOnSetItem).toHaveBeenCalledTimes(1);
+ expect(spyOnSetItem.mock.calls[0][0]).toBe("testInstance_day1_sessionIds");
+ expect(spyOnSetItem.mock.calls[0][1]).toBe(JSON.stringify(["session1"]));
+ });
});
diff --git a/app/static/tests/unit/store/sessions/actions.test.ts b/app/static/tests/unit/store/sessions/actions.test.ts
index 3f8bfa7c4..e339509f1 100644
--- a/app/static/tests/unit/store/sessions/actions.test.ts
+++ b/app/static/tests/unit/store/sessions/actions.test.ts
@@ -14,6 +14,7 @@ import { AppStateGetter } from "../../../../src/app/store/appState/getters";
describe("SessionsActions", () => {
const getSessionIdsSpy = jest.spyOn(localStorageManager, "getSessionIds")
.mockReturnValue(["123", "456"]);
+ const deleteSessionIdSpy = jest.spyOn(localStorageManager, "deleteSessionId");
afterEach(() => {
jest.clearAllTimers();
@@ -314,4 +315,13 @@ describe("SessionsActions", () => {
expect(commit.mock.calls[0][1].detail).toBe("Test Error");
expect(commit.mock.calls[0][2]).toStrictEqual({ root: true });
});
+
+ it("DeleteSession removes from local storage and commits remove session id", async () => {
+ const commit = jest.fn();
+ const rootState = { appName: "testApp" };
+ await (actions[SessionsAction.DeleteSession] as any)({ commit, rootState, rootGetters }, "testSessionId");
+ expect(deleteSessionIdSpy).toHaveBeenCalledWith("testApp", "testInstance", "testSessionId");
+ expect(commit).toHaveBeenCalledTimes(1);
+ expect(commit).toHaveBeenCalledWith(SessionsMutation.RemoveSessionId, "testSessionId");
+ });
});
diff --git a/app/static/tests/unit/store/sessions/mutations.test.ts b/app/static/tests/unit/store/sessions/mutations.test.ts
index f5f09753e..f8532e4de 100644
--- a/app/static/tests/unit/store/sessions/mutations.test.ts
+++ b/app/static/tests/unit/store/sessions/mutations.test.ts
@@ -43,4 +43,18 @@ describe("Sessions mutations", () => {
mutations[SessionsMutation.SetSessionFriendlyId](state, payload);
expect(state.sessionsMetadata).toStrictEqual(sessionsMetadata);
});
+
+ it("RemoveSessionId removes session metadata from state", () => {
+ const sessionsMetadata = [
+ { id: "123" },
+ { id: "456" },
+ { id: "789" }
+ ];
+ const state = { sessionsMetadata } as any;
+ mutations[SessionsMutation.RemoveSessionId](state, "456");
+ expect(state.sessionsMetadata).toStrictEqual([
+ { id: "123" },
+ { id: "789" }
+ ]);
+ });
});