test: add e2e tests for filters on /insights/routing (#21332)
* test: add e2e tests for insights routing filters Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: improve stability of insights routing filters e2e tests Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: address PR feedback for insights routing filters e2e tests Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: add explicit page navigation to resolve timeout issues in filters.e2e.ts Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: navigate to routing tab after loading insights page Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix e2e tests * fix tests * rename * fix tests --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: eunjae@cal.com <hey@eunjae.dev>
This commit is contained in:
co-authored by
Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
eunjae@cal.com <hey@eunjae.dev>
parent
bb98143e2e
commit
25246ef8ff
@@ -9,18 +9,65 @@ export async function selectFilter(page: Page, columnId: string) {
|
||||
await page.getByTestId(`add-filter-item-${columnId}`).click();
|
||||
}
|
||||
|
||||
export async function openFilter(page: Page, columnId: string) {
|
||||
await page.getByTestId(`filter-popover-trigger-${columnId}`).click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a filter with a specific value
|
||||
*/
|
||||
export async function applyFilter(page: Page, columnId: string, value: string) {
|
||||
export async function applySelectFilter(page: Page, columnId: string, value: string) {
|
||||
const existingFilter = page.getByTestId(`filter-popover-trigger-${columnId}`);
|
||||
if (!(await existingFilter.isVisible())) {
|
||||
await selectFilter(page, columnId);
|
||||
}
|
||||
await openFilter(page, columnId);
|
||||
await selectOptionValue(page, columnId, value);
|
||||
await page.keyboard.press("Escape");
|
||||
}
|
||||
|
||||
await page.getByTestId(`filter-popover-trigger-${columnId}`).click();
|
||||
|
||||
export async function selectOptionValue(page: Page, columnId: string, value: string) {
|
||||
await page.getByTestId(`select-filter-options-${columnId}`).getByRole("option", { name: value }).click();
|
||||
}
|
||||
|
||||
export async function applyTextFilter(page: Page, columnId: string, operator: string, operand?: string) {
|
||||
const existingFilter = page.getByTestId(`filter-popover-trigger-${columnId}`);
|
||||
if (!(await existingFilter.isVisible())) {
|
||||
await selectFilter(page, columnId);
|
||||
}
|
||||
await openFilter(page, columnId);
|
||||
|
||||
await page.getByTestId(`text-filter-options-select-${columnId}`).click();
|
||||
await page
|
||||
.locator(`[data-testid="text-filter-options-${columnId}"] [id^="react-select-"]`)
|
||||
.getByText(operator)
|
||||
.first()
|
||||
.click();
|
||||
if (operand) {
|
||||
await page.keyboard.press("Tab");
|
||||
await page.keyboard.type(operand);
|
||||
}
|
||||
await page.keyboard.press("Enter");
|
||||
|
||||
await page.keyboard.press("Escape");
|
||||
}
|
||||
|
||||
export async function applyNumberFilter(page: Page, columnId: string, operator: string, operand: number) {
|
||||
const existingFilter = page.getByTestId(`filter-popover-trigger-${columnId}`);
|
||||
if (!(await existingFilter.isVisible())) {
|
||||
await selectFilter(page, columnId);
|
||||
}
|
||||
await openFilter(page, columnId);
|
||||
|
||||
await page.getByTestId(`number-filter-options-select-${columnId}`).click();
|
||||
await page
|
||||
.locator(`[data-testid="number-filter-options-${columnId}"] [id^="react-select-"]`)
|
||||
.getByText(operator)
|
||||
.first()
|
||||
.click();
|
||||
await page.keyboard.press("Tab");
|
||||
await page.keyboard.type(String(operand));
|
||||
await page.keyboard.press("Enter");
|
||||
|
||||
await page.keyboard.press("Escape");
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { expect } from "@playwright/test";
|
||||
import { MembershipRole } from "@calcom/prisma/enums";
|
||||
|
||||
import {
|
||||
applyFilter,
|
||||
applySelectFilter,
|
||||
createFilterSegment,
|
||||
selectSegment,
|
||||
deleteSegment,
|
||||
@@ -56,7 +56,7 @@ test.describe("Filter Segment Functionality", () => {
|
||||
const segmentName = "Admin Users";
|
||||
|
||||
await test.step("Can apply and save a role filter as a segment", async () => {
|
||||
await applyFilter(page, "role", "admin");
|
||||
await applySelectFilter(page, "role", "admin");
|
||||
|
||||
await expect(page.getByText(adminUser.email)).toBeVisible();
|
||||
await expect(page.getByText(memberUser.email)).toBeHidden();
|
||||
@@ -110,7 +110,7 @@ test.describe("Filter Segment Functionality", () => {
|
||||
const dataTable = page.getByTestId("user-list-data-table");
|
||||
await expect(dataTable).toBeVisible();
|
||||
|
||||
await applyFilter(page, "role", "admin");
|
||||
await applySelectFilter(page, "role", "admin");
|
||||
const segmentName = "Admin Users Persistent";
|
||||
await createFilterSegment(page, segmentName);
|
||||
|
||||
@@ -158,7 +158,7 @@ test.describe("Filter Segment Functionality", () => {
|
||||
const segmentName = "Team Admin Filter";
|
||||
|
||||
await test.step("Can create a team scope filter segment", async () => {
|
||||
await applyFilter(page, "role", "admin");
|
||||
await applySelectFilter(page, "role", "admin");
|
||||
|
||||
await createFilterSegment(page, segmentName, {
|
||||
teamScope: true,
|
||||
|
||||
@@ -0,0 +1,711 @@
|
||||
import { expect } from "@playwright/test";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
import { BookingStatus, MembershipRole } from "@calcom/prisma/enums";
|
||||
|
||||
import {
|
||||
selectFilter,
|
||||
openFilter,
|
||||
clearFilters,
|
||||
applySelectFilter,
|
||||
applyTextFilter,
|
||||
applyNumberFilter,
|
||||
selectOptionValue,
|
||||
} from "./filter-helpers";
|
||||
import { test } from "./lib/fixtures";
|
||||
|
||||
test.afterEach(({ users }) => users.deleteAll());
|
||||
|
||||
test.describe.configure({ mode: "parallel" });
|
||||
|
||||
test.describe("Insights > Routing Filters", () => {
|
||||
test("formId filter: should filter by selected routing form", async ({
|
||||
page,
|
||||
users,
|
||||
routingForms,
|
||||
prisma,
|
||||
}) => {
|
||||
const owner = await users.create(undefined, {
|
||||
hasTeam: true,
|
||||
isUnpublished: true,
|
||||
isOrg: true,
|
||||
hasSubteam: true,
|
||||
});
|
||||
await owner.apiLogin();
|
||||
|
||||
const membership = await owner.getFirstTeamMembership();
|
||||
|
||||
const formName1 = "Test Form 1";
|
||||
const form1 = await routingForms.create({
|
||||
name: formName1,
|
||||
userId: owner.id,
|
||||
teamId: membership.teamId,
|
||||
fields: [
|
||||
{
|
||||
type: "text",
|
||||
label: "Name",
|
||||
identifier: "name",
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const formName2 = "Test Form 2";
|
||||
const form2 = await routingForms.create({
|
||||
name: formName2,
|
||||
userId: owner.id,
|
||||
teamId: membership.teamId,
|
||||
fields: [
|
||||
{
|
||||
type: "text",
|
||||
label: "Email",
|
||||
identifier: "email",
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await page.goto(`/insights/routing`);
|
||||
|
||||
await openFilter(page, "formId");
|
||||
await selectOptionValue(page, "formId", formName1);
|
||||
await page.keyboard.press("Escape");
|
||||
|
||||
await expect(page.getByText(formName1)).toBeVisible();
|
||||
await expect(page.getByText(formName2)).toBeHidden();
|
||||
|
||||
await openFilter(page, "formId");
|
||||
await selectOptionValue(page, "formId", formName2);
|
||||
await page.keyboard.press("Escape");
|
||||
|
||||
await expect(page.getByText(formName2)).toBeVisible();
|
||||
await expect(page.getByText(formName1)).toBeHidden();
|
||||
});
|
||||
|
||||
test("bookingUserId filter: should filter by user", async ({ page, users, routingForms, prisma }) => {
|
||||
const owner = await users.create(
|
||||
{ name: "owner" },
|
||||
{
|
||||
hasTeam: true,
|
||||
isUnpublished: true,
|
||||
isOrg: true,
|
||||
hasSubteam: true,
|
||||
}
|
||||
);
|
||||
const membership = await owner.getFirstTeamMembership();
|
||||
|
||||
const user1Name = "User One";
|
||||
const user1 = await users.create({ name: user1Name });
|
||||
const user2 = await users.create({ name: "User Two" });
|
||||
await prisma.membership.createMany({
|
||||
data: [
|
||||
{
|
||||
teamId: membership.teamId,
|
||||
userId: user1.id,
|
||||
role: MembershipRole.MEMBER,
|
||||
accepted: true,
|
||||
},
|
||||
{
|
||||
teamId: membership.teamId,
|
||||
userId: user2.id,
|
||||
role: MembershipRole.MEMBER,
|
||||
accepted: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await owner.apiLogin();
|
||||
|
||||
const formName = "Filter User Test Form";
|
||||
const form = await routingForms.create({
|
||||
name: formName,
|
||||
userId: owner.id,
|
||||
teamId: membership.teamId,
|
||||
fields: [
|
||||
{
|
||||
type: "text",
|
||||
label: "Name",
|
||||
identifier: "name",
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const booking1 = await prisma.booking.create({
|
||||
data: {
|
||||
uid: `booking-${uuidv4()}`,
|
||||
title: "Test Booking 1",
|
||||
startTime: new Date(),
|
||||
endTime: new Date(Date.now() + 60 * 60 * 1000),
|
||||
userId: user1.id,
|
||||
status: BookingStatus.ACCEPTED,
|
||||
},
|
||||
});
|
||||
|
||||
const booking2 = await prisma.booking.create({
|
||||
data: {
|
||||
uid: `booking-${uuidv4()}`,
|
||||
title: "Test Booking 2",
|
||||
startTime: new Date(),
|
||||
endTime: new Date(Date.now() + 60 * 60 * 1000),
|
||||
userId: user2.id,
|
||||
status: BookingStatus.ACCEPTED,
|
||||
},
|
||||
});
|
||||
|
||||
const fieldId = (form.fields as any)[0].id;
|
||||
await prisma.app_RoutingForms_FormResponse.create({
|
||||
data: {
|
||||
formFillerId: "test-filler-1",
|
||||
formId: form.id,
|
||||
response: {
|
||||
[fieldId]: {
|
||||
label: "Name",
|
||||
value: "John Doe",
|
||||
},
|
||||
},
|
||||
routedToBookingUid: booking1.uid,
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.app_RoutingForms_FormResponse.create({
|
||||
data: {
|
||||
formFillerId: "test-filler-2",
|
||||
formId: form.id,
|
||||
response: {
|
||||
[fieldId]: {
|
||||
label: "Name",
|
||||
value: "Jane Smith",
|
||||
},
|
||||
},
|
||||
routedToBookingUid: booking2.uid,
|
||||
},
|
||||
});
|
||||
|
||||
await page.goto(`/insights/routing`);
|
||||
|
||||
await applySelectFilter(page, "bookingUserId", user1Name);
|
||||
|
||||
await expect(page.getByText("John Doe")).toBeVisible();
|
||||
await expect(page.getByText("Jane Smith")).toBeHidden();
|
||||
|
||||
await prisma.booking.delete({ where: { id: booking1.id } });
|
||||
await prisma.booking.delete({ where: { id: booking2.id } });
|
||||
});
|
||||
|
||||
// We will add it back when we enable the bookingAttendees filter on /insights/routing
|
||||
test.skip("bookingAttendees filter: should filter by attendee name or email", async ({
|
||||
page,
|
||||
users,
|
||||
routingForms,
|
||||
prisma,
|
||||
}) => {
|
||||
const owner = await users.create(undefined, {
|
||||
hasTeam: true,
|
||||
isUnpublished: true,
|
||||
isOrg: true,
|
||||
hasSubteam: true,
|
||||
});
|
||||
await owner.apiLogin();
|
||||
|
||||
const membership = await owner.getFirstTeamMembership();
|
||||
|
||||
const formName = "Attendee Filter Test Form";
|
||||
const form = await routingForms.create({
|
||||
name: formName,
|
||||
userId: owner.id,
|
||||
teamId: membership.teamId,
|
||||
fields: [
|
||||
{
|
||||
type: "text",
|
||||
label: "Name",
|
||||
identifier: "name",
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
const fieldId = (form.fields as any)[0].id;
|
||||
|
||||
const booking1 = await prisma.booking.create({
|
||||
data: {
|
||||
uid: `booking-${uuidv4()}`,
|
||||
title: "Test Booking 1",
|
||||
startTime: new Date(),
|
||||
endTime: new Date(Date.now() + 60 * 60 * 1000),
|
||||
userId: owner.id,
|
||||
status: BookingStatus.ACCEPTED,
|
||||
attendees: {
|
||||
create: [
|
||||
{
|
||||
email: "john.doe@example.com",
|
||||
name: "John Doe",
|
||||
timeZone: "UTC",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const booking2 = await prisma.booking.create({
|
||||
data: {
|
||||
uid: `booking-${uuidv4()}`,
|
||||
title: "Test Booking 2",
|
||||
startTime: new Date(),
|
||||
endTime: new Date(Date.now() + 60 * 60 * 1000),
|
||||
userId: owner.id,
|
||||
status: BookingStatus.ACCEPTED,
|
||||
attendees: {
|
||||
create: [
|
||||
{
|
||||
email: "jane.smith@example.com",
|
||||
name: "Jane Smith",
|
||||
timeZone: "UTC",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.app_RoutingForms_FormResponse.create({
|
||||
data: {
|
||||
formFillerId: "test-filler-1",
|
||||
formId: form.id,
|
||||
response: { [fieldId]: { label: "Name", value: "Response 1" } },
|
||||
routedToBookingUid: booking1.uid,
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.app_RoutingForms_FormResponse.create({
|
||||
data: {
|
||||
formFillerId: "test-filler-2",
|
||||
formId: form.id,
|
||||
response: { [fieldId]: { label: "Name", value: "Response 2" } },
|
||||
routedToBookingUid: booking2.uid,
|
||||
},
|
||||
});
|
||||
|
||||
await page.goto(`/insights/routing`);
|
||||
|
||||
await selectFilter(page, "bookingAttendees");
|
||||
await openFilter(page, "bookingAttendees");
|
||||
await page.getByPlaceholder("Filter attendees by name or email").fill("John");
|
||||
await page.keyboard.press("Enter");
|
||||
|
||||
await expect(page.getByText("Response 1")).toBeVisible();
|
||||
await expect(page.getByText("Response 2")).toBeHidden();
|
||||
|
||||
await clearFilters(page);
|
||||
await selectFilter(page, "bookingAttendees");
|
||||
await openFilter(page, "bookingAttendees");
|
||||
await page.getByPlaceholder("Filter attendees by name or email").fill("jane.smith@example");
|
||||
await page.keyboard.press("Enter");
|
||||
|
||||
await expect(page.getByText("Response 2")).toBeVisible();
|
||||
await expect(page.getByText("Response 1")).toBeHidden();
|
||||
|
||||
await clearFilters(page);
|
||||
await selectFilter(page, "bookingAttendees");
|
||||
await openFilter(page, "bookingAttendees");
|
||||
await page.getByPlaceholder("Filter attendees by name or email").fill("JANE");
|
||||
await page.keyboard.press("Enter");
|
||||
|
||||
await expect(page.getByText("Response 2")).toBeVisible();
|
||||
await expect(page.getByText("Response 1")).toBeHidden();
|
||||
|
||||
await prisma.booking.delete({ where: { id: booking1.id } });
|
||||
await prisma.booking.delete({ where: { id: booking2.id } });
|
||||
});
|
||||
|
||||
test("TEXT field: should filter with different text operators", async ({
|
||||
page,
|
||||
users,
|
||||
routingForms,
|
||||
prisma,
|
||||
}) => {
|
||||
const owner = await users.create(undefined, {
|
||||
hasTeam: true,
|
||||
isUnpublished: true,
|
||||
isOrg: true,
|
||||
hasSubteam: true,
|
||||
});
|
||||
await owner.apiLogin();
|
||||
|
||||
const membership = await owner.getFirstTeamMembership();
|
||||
|
||||
const textFieldId = uuidv4();
|
||||
const formName = "Text Filter Test Form";
|
||||
const form = await routingForms.create({
|
||||
name: formName,
|
||||
userId: owner.id,
|
||||
teamId: membership.teamId,
|
||||
fields: [
|
||||
{
|
||||
type: "text",
|
||||
label: "Description",
|
||||
identifier: "description",
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
const fieldId = (form.fields as any)[0].id;
|
||||
|
||||
await prisma.app_RoutingForms_FormResponse.create({
|
||||
data: {
|
||||
formFillerId: "test-filler-1",
|
||||
formId: form.id,
|
||||
response: {
|
||||
[fieldId]: {
|
||||
label: "Description",
|
||||
value: "This is a test description",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.app_RoutingForms_FormResponse.create({
|
||||
data: {
|
||||
formFillerId: "test-filler-2",
|
||||
formId: form.id,
|
||||
response: {
|
||||
[fieldId]: {
|
||||
label: "Description",
|
||||
value: "Another description for testing",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.app_RoutingForms_FormResponse.create({
|
||||
data: {
|
||||
formFillerId: "test-filler-3",
|
||||
formId: form.id,
|
||||
response: {
|
||||
[fieldId]: {
|
||||
label: "Description",
|
||||
value: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await page.goto(`/insights/routing`);
|
||||
|
||||
await applyTextFilter(page, fieldId, "Contains", "test");
|
||||
|
||||
await expect(page.getByText("This is a test description")).toBeVisible();
|
||||
await expect(page.getByText("Another description for testing")).toBeVisible();
|
||||
|
||||
await clearFilters(page);
|
||||
await applyTextFilter(page, fieldId, "Is", "This is a test description");
|
||||
|
||||
await expect(page.getByText("This is a test description")).toBeVisible();
|
||||
await expect(page.getByText("Another description for testing")).toBeHidden();
|
||||
|
||||
await clearFilters(page);
|
||||
await applyTextFilter(page, fieldId, "Is empty");
|
||||
|
||||
await expect(page.getByText("This is a test description")).toBeHidden();
|
||||
await expect(page.getByText("Another description for testing")).toBeHidden();
|
||||
|
||||
await clearFilters(page);
|
||||
await applyTextFilter(page, fieldId, "Contains", "TEST");
|
||||
|
||||
await expect(page.getByText("This is a test description")).toBeVisible();
|
||||
await expect(page.getByText("Another description for testing")).toBeVisible();
|
||||
});
|
||||
|
||||
test("NUMBER field: should filter with different number operators", async ({
|
||||
page,
|
||||
users,
|
||||
routingForms,
|
||||
prisma,
|
||||
}) => {
|
||||
const owner = await users.create(undefined, {
|
||||
hasTeam: true,
|
||||
isUnpublished: true,
|
||||
isOrg: true,
|
||||
hasSubteam: true,
|
||||
});
|
||||
await owner.apiLogin();
|
||||
|
||||
const membership = await owner.getFirstTeamMembership();
|
||||
|
||||
const formName = "Number Filter Test Form";
|
||||
const form = await routingForms.create({
|
||||
name: formName,
|
||||
userId: owner.id,
|
||||
teamId: membership.teamId,
|
||||
fields: [
|
||||
{
|
||||
type: "number",
|
||||
label: "Rating",
|
||||
identifier: "rating",
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
const fieldId = (form.fields as any)[0].id;
|
||||
|
||||
await prisma.app_RoutingForms_FormResponse.create({
|
||||
data: {
|
||||
formFillerId: "test-filler-1",
|
||||
formId: form.id,
|
||||
response: {
|
||||
[fieldId]: {
|
||||
label: "Rating",
|
||||
value: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.app_RoutingForms_FormResponse.create({
|
||||
data: {
|
||||
formFillerId: "test-filler-2",
|
||||
formId: form.id,
|
||||
response: {
|
||||
[fieldId]: {
|
||||
label: "Rating",
|
||||
value: 3,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.app_RoutingForms_FormResponse.create({
|
||||
data: {
|
||||
formFillerId: "test-filler-3",
|
||||
formId: form.id,
|
||||
response: {
|
||||
[fieldId]: {
|
||||
label: "Rating",
|
||||
value: 5,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await page.goto(`/insights/routing`);
|
||||
|
||||
await applyNumberFilter(page, fieldId, "=", 3);
|
||||
|
||||
const getByNumber = (number: number) =>
|
||||
page.locator(`[data-testid="data-table-td-${fieldId}"]`).getByText(String(number));
|
||||
|
||||
await expect(getByNumber(3)).toBeVisible();
|
||||
await expect(getByNumber(1)).toBeHidden();
|
||||
await expect(getByNumber(5)).toBeHidden();
|
||||
|
||||
await clearFilters(page);
|
||||
await applyNumberFilter(page, fieldId, ">", 3);
|
||||
|
||||
await expect(getByNumber(5)).toBeVisible();
|
||||
await expect(getByNumber(1)).toBeHidden();
|
||||
await expect(getByNumber(3)).toBeHidden();
|
||||
|
||||
await clearFilters(page);
|
||||
await applyNumberFilter(page, fieldId, "≤", 3);
|
||||
|
||||
await expect(getByNumber(1)).toBeVisible();
|
||||
await expect(getByNumber(3)).toBeVisible();
|
||||
await expect(getByNumber(5)).toBeHidden();
|
||||
});
|
||||
|
||||
test("SINGLE_SELECT and MULTI_SELECT fields: should filter correctly", async ({
|
||||
page,
|
||||
users,
|
||||
routingForms,
|
||||
prisma,
|
||||
}) => {
|
||||
const owner = await users.create(undefined, {
|
||||
hasTeam: true,
|
||||
isUnpublished: true,
|
||||
isOrg: true,
|
||||
hasSubteam: true,
|
||||
});
|
||||
await owner.apiLogin();
|
||||
|
||||
const membership = await owner.getFirstTeamMembership();
|
||||
|
||||
const singleSelectFieldId = uuidv4();
|
||||
const multiSelectFieldId = uuidv4();
|
||||
const formName = "Select Filter Test Form";
|
||||
|
||||
const locationOptionId1 = uuidv4();
|
||||
const locationOptionId2 = uuidv4();
|
||||
|
||||
const skillOptionId1 = uuidv4();
|
||||
const skillOptionId2 = uuidv4();
|
||||
const skillOptionId3 = uuidv4();
|
||||
|
||||
const form = await routingForms.create({
|
||||
name: formName,
|
||||
userId: owner.id,
|
||||
teamId: membership.teamId,
|
||||
fields: [
|
||||
{
|
||||
type: "select",
|
||||
label: "Location",
|
||||
identifier: "location",
|
||||
required: true,
|
||||
options: [
|
||||
{
|
||||
id: locationOptionId1,
|
||||
label: "New York",
|
||||
},
|
||||
{
|
||||
id: locationOptionId2,
|
||||
label: "London",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "multiselect",
|
||||
label: "Skills",
|
||||
identifier: "skills",
|
||||
required: true,
|
||||
options: [
|
||||
{
|
||||
id: skillOptionId1,
|
||||
label: "JavaScript",
|
||||
},
|
||||
{
|
||||
id: skillOptionId2,
|
||||
label: "TypeScript",
|
||||
},
|
||||
{
|
||||
id: skillOptionId3,
|
||||
label: "React",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
const locationFieldId = (form.fields as any)[0].id;
|
||||
const skillFieldId = (form.fields as any)[1].id;
|
||||
|
||||
await prisma.app_RoutingForms_FormResponse.create({
|
||||
data: {
|
||||
formFillerId: "test-filler-1",
|
||||
formId: form.id,
|
||||
response: {
|
||||
[locationFieldId]: {
|
||||
label: "Location",
|
||||
value: locationOptionId1,
|
||||
},
|
||||
[skillFieldId]: {
|
||||
label: "Skills",
|
||||
value: [skillOptionId1, skillOptionId2],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.app_RoutingForms_FormResponse.create({
|
||||
data: {
|
||||
formFillerId: "test-filler-2",
|
||||
formId: form.id,
|
||||
response: {
|
||||
[locationFieldId]: {
|
||||
label: "Location",
|
||||
value: locationOptionId2,
|
||||
},
|
||||
[skillFieldId]: {
|
||||
label: "Skills",
|
||||
value: [skillOptionId2, skillOptionId3],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await page.goto(`/insights/routing`);
|
||||
|
||||
const getByColumnValue = (columnId: string, value: string) =>
|
||||
page.locator(`[data-testid="data-table-td-${columnId}"]`).getByText(value);
|
||||
|
||||
await applySelectFilter(page, locationFieldId, "New York");
|
||||
await expect(getByColumnValue(locationFieldId, "New York")).toBeVisible();
|
||||
await expect(getByColumnValue(locationFieldId, "London")).toBeHidden();
|
||||
|
||||
await clearFilters(page);
|
||||
await applySelectFilter(page, skillFieldId, "JavaScript");
|
||||
await applySelectFilter(page, skillFieldId, "TypeScript");
|
||||
await expect(getByColumnValue(skillFieldId, "JavaScript")).toBeVisible();
|
||||
await expect(getByColumnValue(skillFieldId, "TypeScript")).toBeVisible();
|
||||
await expect(getByColumnValue(skillFieldId, "React")).toBeHidden();
|
||||
});
|
||||
|
||||
test("createdAt filter: should filter by date range", async ({ page, users, routingForms, prisma }) => {
|
||||
const owner = await users.create(undefined, {
|
||||
hasTeam: true,
|
||||
isUnpublished: true,
|
||||
isOrg: true,
|
||||
hasSubteam: true,
|
||||
});
|
||||
await owner.apiLogin();
|
||||
|
||||
const membership = await owner.getFirstTeamMembership();
|
||||
|
||||
const formName = "Date Range Filter Test Form";
|
||||
const form = await routingForms.create({
|
||||
name: formName,
|
||||
userId: owner.id,
|
||||
teamId: membership.teamId,
|
||||
fields: [
|
||||
{
|
||||
type: "text",
|
||||
label: "Name",
|
||||
identifier: "name",
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
const fieldId = (form.fields as any)[0].id;
|
||||
|
||||
const oldDate = new Date();
|
||||
oldDate.setDate(oldDate.getDate() - 10);
|
||||
|
||||
await prisma.app_RoutingForms_FormResponse.create({
|
||||
data: {
|
||||
formFillerId: "test-filler-old",
|
||||
formId: form.id,
|
||||
response: {
|
||||
[fieldId]: {
|
||||
label: "Name",
|
||||
value: "Old Response",
|
||||
},
|
||||
},
|
||||
createdAt: oldDate,
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.app_RoutingForms_FormResponse.create({
|
||||
data: {
|
||||
formFillerId: "test-filler-recent",
|
||||
formId: form.id,
|
||||
response: {
|
||||
[fieldId]: {
|
||||
label: "Name",
|
||||
value: "Recent Response",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await page.goto(`/insights/routing`);
|
||||
|
||||
await openFilter(page, "createdAt");
|
||||
await page.getByTestId("date-range-options-w").click(); // Last 7 Days
|
||||
await page.keyboard.press("Escape");
|
||||
|
||||
await expect(page.getByText("Recent Response")).toBeVisible();
|
||||
await expect(page.getByText("Old Response")).toBeHidden();
|
||||
|
||||
await openFilter(page, "createdAt");
|
||||
await page.getByTestId("date-range-options-t").click(); // Last 30 Days
|
||||
await page.keyboard.press("Escape");
|
||||
|
||||
await expect(page.getByText("Recent Response")).toBeVisible();
|
||||
await expect(page.getByText("Old Response")).toBeVisible();
|
||||
});
|
||||
});
|
||||
@@ -312,6 +312,7 @@ function DataTableBody<TData>({
|
||||
return (
|
||||
<TableCell
|
||||
key={cell.id}
|
||||
data-testid={`data-table-td-${cell.column.id}`}
|
||||
style={{
|
||||
...(column.getIsPinned() === "left" && { left: `${column.getStart("left")}px` }),
|
||||
...(column.getIsPinned() === "right" && { right: `${column.getStart("right")}px` }),
|
||||
|
||||
@@ -30,7 +30,7 @@ export function NumberFilterOptions({ column }: NumberFilterOptionsProps) {
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="mx-3 my-2">
|
||||
<div className="mx-3 my-2" data-testid={`number-filter-options-${column.id}`}>
|
||||
<Form
|
||||
form={form}
|
||||
handleSubmit={({ operatorOption, operand }) => {
|
||||
@@ -51,6 +51,7 @@ export function NumberFilterOptions({ column }: NumberFilterOptionsProps) {
|
||||
render={({ field: { value } }) => (
|
||||
<div className="flex items-center gap-2">
|
||||
<Select
|
||||
data-testid={`number-filter-options-select-${column.id}`}
|
||||
className="basis-1/3"
|
||||
options={numberFilterOperatorOptions}
|
||||
value={value}
|
||||
|
||||
@@ -31,7 +31,7 @@ export function TextFilterOptions({ column }: TextFilterOptionsProps) {
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="mx-3 my-2">
|
||||
<div className="mx-3 my-2" data-testid={`text-filter-options-${column.id}`}>
|
||||
<Form
|
||||
form={form}
|
||||
handleSubmit={({ operatorOption, operand }) => {
|
||||
@@ -52,6 +52,7 @@ export function TextFilterOptions({ column }: TextFilterOptionsProps) {
|
||||
render={({ field: { value } }) => (
|
||||
<>
|
||||
<Select
|
||||
data-testid={`text-filter-options-select-${column.id}`}
|
||||
options={textFilterOperatorOptions}
|
||||
value={value}
|
||||
isSearchable={false}
|
||||
|
||||
Reference in New Issue
Block a user