Skip to content
Open
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
8 changes: 7 additions & 1 deletion echo/cypress/cypress.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,16 @@ module.exports = defineConfig({
config.baseUrl = envConfig.dashboardUrl;

// Merge the specific environment config to the top level of config.env
// So in tests we can do Cypress.env('auth') or Cypress.env('portalUrl') directly
// So in tests we can do Cypress.env('auth') or Cypress.env('portalUrl') directly.
// Credentials come from env vars first so tracked config stays credential-free.
const envAuth = envConfig.auth || {};
config.env = {
...config.env,
...envConfig,
auth: {
email: process.env.CYPRESS_EMAIL || envAuth.email || "",
password: process.env.CYPRESS_PASSWORD || envAuth.password || "",
},
};

return config;
Expand Down
23 changes: 16 additions & 7 deletions echo/cypress/cypress.env.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,33 @@
"dashboardUrl": "https://dashboard.echo-next.dembrane.com/",
"portalUrl": "https://portal.echo-next.dembrane.com/",
"auth": {
"email": "charugundla.vipul6009@gmail.com",
"password": "test@1234"
"email": "",
"password": ""
}
},
"prod": {
"dashboardUrl": "https://dashboard.echo.dembrane.com/",
"portalUrl": "https://portal.echo.dembrane.com/",
"auth": {
"email": "charugundla.vipul6009@gmail.com",
"password": "test@1234"
"email": "",
"password": ""
}
},
"testing": {
"dashboardUrl": "https://test.echo.dembrane.com/",
"portalUrl": "https://test.portal.echo.dembrane.com/",
"auth": {
"email": "charugundla.vipul6009@gmail.com",
"password": "test@1234"
"email": "",
"password": ""
}
},
"local": {
"dashboardUrl": "http://localhost:5173/",
"portalUrl": "http://localhost:5174/",
"directusUrl": "http://localhost:8055",
"auth": {
"email": "",
"password": ""
}
}
}
}
224 changes: 224 additions & 0 deletions echo/cypress/e2e/suites/34-live-signposts.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
import { loginToApp, logout } from "../../support/functions/login";
import { openPortalEditor } from "../../support/functions/portal";
import { createProject, deleteProject } from "../../support/functions/project";
import { openSettingsMenu } from "../../support/functions/settings";

describe("Live Signposts", () => {
const directusUrl = (Cypress.env("directusUrl") || "http://localhost:8055").replace(
/\/$/,
"",
);
let projectId;
let locale = "en-US";

const getAuthCredentials = () => {
const auth = Cypress.env("auth") || {};
if (!auth.email || !auth.password) {
throw new Error(
"Missing Directus credentials. Set CYPRESS_EMAIL and CYPRESS_PASSWORD.",
);
}
return auth;
};

const getFocusTermsTextarea = () =>
cy
.get('[data-testid="portal-editor-signposting-focus-terms-textarea"]')
.then(($element) => {
const $textarea = $element.is("textarea")
? $element
: $element.find("textarea").first();
return cy.wrap($textarea);
});

const toggleLiveSignposting = (enable = true) => {
cy.get('[data-testid="portal-editor-signposting-switch"]')
.scrollIntoView()
.should("exist")
.then(($input) => {
const $label = $input.closest("label");
const isChecked = $input.is(":checked");

if ((enable && !isChecked) || (!enable && isChecked)) {
cy.wrap($label).click({ force: true });
}
});

cy.get('[data-testid="portal-editor-signposting-switch"]').should(
enable ? "be.checked" : "not.be.checked",
);
};

const loginToDirectus = () => {
const auth = getAuthCredentials();
return cy
.request("POST", `${directusUrl}/auth/login`, {
email: auth.email,
password: auth.password,
})
.its("body.data.access_token");
};

afterEach(() => {
if (projectId) {
cy.visit(`/${locale}/projects/${projectId}/overview`);
deleteProject(projectId);
}

cy.get("body").then(($body) => {
const hasSettingsButton =
$body.find('[data-testid="header-settings-gear-button"]:visible').length > 0;
const hasLogoutButton =
$body.find('[data-testid="header-logout-menu-item"]:visible').length > 0;

if (hasSettingsButton) {
openSettingsMenu();
logout();
} else if (hasLogoutButton) {
logout();
}
});

projectId = undefined;
locale = "en-US";
});

const seedConversationWithSignposts = ({ locale, projectId }) => {
const suffix = Cypress._.random(1000, 9999);
const signpostTitle = `Transit affordability ${suffix}`;
const signpostSummary =
"Participants keep returning to the rising cost of buses and trains.";
const signpostQuote = "Public transport is becoming too expensive for families.";

return loginToDirectus().then((accessToken) => {
const headers = {
Authorization: `Bearer ${accessToken}`,
};

return cy
.request({
body: {
is_finished: false,
participant_name: `Signpost Participant ${suffix}`,
project_id: projectId,
source: "PORTAL_TEXT",
},
headers,
method: "POST",
url: `${directusUrl}/items/conversation`,
})
.then((conversationResponse) => {
const conversationId = conversationResponse.body.data.id;
const timestamp = new Date().toISOString();

return cy
.request({
body: {
conversation_id: conversationId,
signpost_processed_at: timestamp,
signpost_ready_at: timestamp,
source: "PORTAL_TEXT",
timestamp,
transcript:
"People agree that public transport costs are rising quickly.",
},
headers,
method: "POST",
url: `${directusUrl}/items/conversation_chunk`,
})
.then((chunkResponse) => {
const chunkId = chunkResponse.body.data.id;

return cy
.request({
body: {
category: "theme",
confidence: 0.92,
conversation_id: conversationId,
evidence_chunk_id: chunkId,
evidence_quote: signpostQuote,
status: "active",
summary: signpostSummary,
title: signpostTitle,
},
headers,
method: "POST",
url: `${directusUrl}/items/conversation_signpost`,
})
.then((signpostResponse) => ({
conversationId,
locale,
projectId,
signpostId: signpostResponse.body.data.id,
signpostQuote,
signpostSummary,
signpostTitle,
}));
});
});
});
};

it("shows seeded signposts in portal settings, conversation overview, and host guide", () => {
loginToApp();
createProject();

cy.location("pathname").then((pathname) => {
const segments = pathname.split("/").filter(Boolean);
projectId = segments[segments.indexOf("projects") + 1];
locale = segments[0] || locale;
});

openPortalEditor();
toggleLiveSignposting(true);
cy.intercept("PATCH", `${directusUrl}/items/project/*`, (req) => {
const focusTerms = req.body?.signposting_focus_terms;
if (
typeof focusTerms === "string" &&
focusTerms.includes("public transport")
) {
req.alias = "saveSignpostingFocusTerms";
}
});
getFocusTermsTextarea()
.scrollIntoView()
.clear()
.type("affordability{enter}public transport");
cy.wait("@saveSignpostingFocusTerms");

cy.reload();
openPortalEditor();
cy.get('[data-testid="portal-editor-signposting-switch"]').should("be.checked");
getFocusTermsTextarea().should(
"have.value",
"affordability\npublic transport",
);

cy.then(() => seedConversationWithSignposts({ locale, projectId })).then(
({ conversationId, signpostId, signpostQuote, signpostSummary, signpostTitle }) => {
cy.visit(
`/${locale}/projects/${projectId}/conversation/${conversationId}/overview`,
);

cy.get('[data-testid="conversation-signposts-section"]', {
timeout: 20000,
}).should("be.visible");
cy.get(`[data-testid="conversation-signpost-card-${signpostId}"]`)
.should("contain.text", signpostTitle)
.and("contain.text", signpostSummary)
.and("contain.text", signpostQuote);

cy.visit(`/${locale}/projects/${projectId}/host-guide`);

cy.get('[data-testid="host-guide-live-signposts-panel"]', {
timeout: 30000,
}).should("be.visible");
cy.get(`[data-testid="host-guide-live-signpost-${signpostId}"]`, {
timeout: 30000,
})
.should("contain.text", signpostTitle)
.and("contain.text", signpostSummary);
},
);
});
});
6 changes: 3 additions & 3 deletions echo/cypress/support/functions/login/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
export const loginToApp = () => {
cy.log('Logging in with data-testid selectors');
const user = Cypress.env('auth');
const user = Cypress.env('auth') || {};

if (!user || !user.email) {
throw new Error('User credentials not found in environment configuration.');
if (!user.email || !user.password) {
throw new Error('User credentials not found. Set CYPRESS_EMAIL and CYPRESS_PASSWORD.');
}

cy.visit('/');
Expand Down
28 changes: 28 additions & 0 deletions echo/directus/sync/snapshot/collections/conversation_signpost.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"collection": "conversation_signpost",
"meta": {
"accountability": "all",
"archive_app_filter": true,
"archive_field": null,
"archive_value": null,
"collapse": "open",
"collection": "conversation_signpost",
"color": null,
"display_template": "{{title}}",
"group": null,
"hidden": false,
"icon": null,
"item_duplication_fields": null,
"note": null,
"preview_url": null,
"singleton": false,
"sort": 14,
"sort_field": null,
"translations": null,
"unarchive_value": null,
"versioning": false
},
"schema": {
"name": "conversation_signpost"
}
}
28 changes: 28 additions & 0 deletions echo/directus/sync/snapshot/fields/conversation/signposts.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"collection": "conversation",
"field": "signposts",
"type": "alias",
"meta": {
"collection": "conversation",
"conditions": null,
"display": null,
"display_options": null,
"field": "signposts",
"group": null,
"hidden": false,
"interface": "list-o2m",
"note": null,
"options": null,
"readonly": false,
"required": false,
"searchable": true,
"sort": 28,
"special": [
"o2m"
],
"translations": null,
"validation": null,
"validation_message": null,
"width": "full"
}
}
Loading
Loading