mirror of
https://github.com/formbricks/formbricks.git
synced 2026-01-01 11:20:26 -06:00
Compare commits
2 Commits
fix/attrib
...
fix-data-r
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd8bba598f | ||
|
|
d4856a9b32 |
@@ -1,9 +1,3 @@
|
|||||||
import { getQuotasSummary } from "@/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/lib/survey";
|
|
||||||
import { getDisplayCountBySurveyId } from "@/lib/display/service";
|
|
||||||
import { getLocalizedValue } from "@/lib/i18n/utils";
|
|
||||||
import { getResponseCountBySurveyId } from "@/lib/response/service";
|
|
||||||
import { getSurvey } from "@/lib/survey/service";
|
|
||||||
import { evaluateLogic, performActions } from "@/lib/surveyLogic/utils";
|
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { beforeEach, describe, expect, test, vi } from "vitest";
|
import { beforeEach, describe, expect, test, vi } from "vitest";
|
||||||
import { prisma } from "@formbricks/database";
|
import { prisma } from "@formbricks/database";
|
||||||
@@ -16,6 +10,12 @@ import {
|
|||||||
TSurveyQuestionTypeEnum,
|
TSurveyQuestionTypeEnum,
|
||||||
TSurveySummary,
|
TSurveySummary,
|
||||||
} from "@formbricks/types/surveys/types";
|
} from "@formbricks/types/surveys/types";
|
||||||
|
import { getQuotasSummary } from "@/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/lib/survey";
|
||||||
|
import { getDisplayCountBySurveyId } from "@/lib/display/service";
|
||||||
|
import { getLocalizedValue } from "@/lib/i18n/utils";
|
||||||
|
import { getResponseCountBySurveyId } from "@/lib/response/service";
|
||||||
|
import { getSurvey } from "@/lib/survey/service";
|
||||||
|
import { evaluateLogic, performActions } from "@/lib/surveyLogic/utils";
|
||||||
import {
|
import {
|
||||||
getQuestionSummary,
|
getQuestionSummary,
|
||||||
getResponsesForSummary,
|
getResponsesForSummary,
|
||||||
@@ -376,6 +376,102 @@ describe("getQuestionSummary", () => {
|
|||||||
expect(openTextSummary?.samples[0].value).toBe("Open answer");
|
expect(openTextSummary?.samples[0].value).toBe("Open answer");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("summarizes OpenText questions with array answer format", async () => {
|
||||||
|
const responsesWithArray = [
|
||||||
|
{
|
||||||
|
id: "r1",
|
||||||
|
data: { q_open: ["Answer 1", "Answer 2", "Answer 3"] },
|
||||||
|
updatedAt: new Date(),
|
||||||
|
contact: null,
|
||||||
|
contactAttributes: {},
|
||||||
|
language: "en",
|
||||||
|
ttc: {},
|
||||||
|
finished: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const summary = await getQuestionSummary(survey, responsesWithArray, mockDropOff);
|
||||||
|
const openTextSummary = summary.find((s: any) => s.question?.id === "q_open");
|
||||||
|
expect(openTextSummary?.type).toBe(TSurveyQuestionTypeEnum.OpenText);
|
||||||
|
expect(openTextSummary?.responseCount).toBe(1);
|
||||||
|
// @ts-expect-error
|
||||||
|
expect(openTextSummary?.samples[0].value).toBe("Answer 1, Answer 2, Answer 3");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("summarizes OpenText questions with array containing null/empty values", async () => {
|
||||||
|
const responsesWithPartialArray = [
|
||||||
|
{
|
||||||
|
id: "r1",
|
||||||
|
data: { q_open: ["Valid answer", null, "", "Another answer", undefined] },
|
||||||
|
updatedAt: new Date(),
|
||||||
|
contact: null,
|
||||||
|
contactAttributes: {},
|
||||||
|
language: "en",
|
||||||
|
ttc: {},
|
||||||
|
finished: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const summary = await getQuestionSummary(survey, responsesWithPartialArray, mockDropOff);
|
||||||
|
const openTextSummary = summary.find((s: any) => s.question?.id === "q_open");
|
||||||
|
expect(openTextSummary?.type).toBe(TSurveyQuestionTypeEnum.OpenText);
|
||||||
|
expect(openTextSummary?.responseCount).toBe(1);
|
||||||
|
// @ts-expect-error - filters out null, empty string, and undefined
|
||||||
|
expect(openTextSummary?.samples[0].value).toBe("Valid answer, Another answer");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("summarizes OpenText questions ignoring empty arrays", async () => {
|
||||||
|
const responsesWithEmptyArray = [
|
||||||
|
{
|
||||||
|
id: "r1",
|
||||||
|
data: { q_open: [] },
|
||||||
|
updatedAt: new Date(),
|
||||||
|
contact: null,
|
||||||
|
contactAttributes: {},
|
||||||
|
language: "en",
|
||||||
|
ttc: {},
|
||||||
|
finished: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const summary = await getQuestionSummary(survey, responsesWithEmptyArray, mockDropOff);
|
||||||
|
const openTextSummary = summary.find((s: any) => s.question?.id === "q_open");
|
||||||
|
expect(openTextSummary?.type).toBe(TSurveyQuestionTypeEnum.OpenText);
|
||||||
|
expect(openTextSummary?.responseCount).toBe(0);
|
||||||
|
// @ts-expect-error
|
||||||
|
expect(openTextSummary?.samples).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("summarizes OpenText questions with mixed string and array responses", async () => {
|
||||||
|
const mixedResponses = [
|
||||||
|
{
|
||||||
|
id: "r1",
|
||||||
|
data: { q_open: "String answer" },
|
||||||
|
updatedAt: new Date(),
|
||||||
|
contact: null,
|
||||||
|
contactAttributes: {},
|
||||||
|
language: "en",
|
||||||
|
ttc: {},
|
||||||
|
finished: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "r2",
|
||||||
|
data: { q_open: ["Array", "answer"] },
|
||||||
|
updatedAt: new Date(),
|
||||||
|
contact: null,
|
||||||
|
contactAttributes: {},
|
||||||
|
language: "en",
|
||||||
|
ttc: {},
|
||||||
|
finished: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const summary = await getQuestionSummary(survey, mixedResponses, mockDropOff);
|
||||||
|
const openTextSummary = summary.find((s: any) => s.question?.id === "q_open");
|
||||||
|
expect(openTextSummary?.type).toBe(TSurveyQuestionTypeEnum.OpenText);
|
||||||
|
expect(openTextSummary?.responseCount).toBe(2);
|
||||||
|
// @ts-expect-error
|
||||||
|
expect(openTextSummary?.samples[0].value).toBe("String answer");
|
||||||
|
// @ts-expect-error
|
||||||
|
expect(openTextSummary?.samples[1].value).toBe("Array, answer");
|
||||||
|
});
|
||||||
|
|
||||||
test("summarizes MultipleChoiceSingle questions", async () => {
|
test("summarizes MultipleChoiceSingle questions", async () => {
|
||||||
const summary = await getQuestionSummary(survey, responses, mockDropOff);
|
const summary = await getQuestionSummary(survey, responses, mockDropOff);
|
||||||
const multiSingleSummary = summary.find((s: any) => s.question?.id === "q_multi_single");
|
const multiSingleSummary = summary.find((s: any) => s.question?.id === "q_multi_single");
|
||||||
|
|||||||
@@ -322,11 +322,18 @@ export const getQuestionSummary = async (
|
|||||||
let values: TSurveyQuestionSummaryOpenText["samples"] = [];
|
let values: TSurveyQuestionSummaryOpenText["samples"] = [];
|
||||||
responses.forEach((response) => {
|
responses.forEach((response) => {
|
||||||
const answer = response.data[question.id];
|
const answer = response.data[question.id];
|
||||||
if (answer && typeof answer === "string") {
|
let normalizedAnswer: string | null = null;
|
||||||
|
if (typeof answer === "string" && answer) {
|
||||||
|
normalizedAnswer = answer;
|
||||||
|
} else if (Array.isArray(answer) && answer.length > 0) {
|
||||||
|
normalizedAnswer = answer.filter((v) => v != null && v !== "").join(", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (normalizedAnswer) {
|
||||||
values.push({
|
values.push({
|
||||||
id: response.id,
|
id: response.id,
|
||||||
updatedAt: response.updatedAt,
|
updatedAt: response.updatedAt,
|
||||||
value: answer,
|
value: normalizedAnswer,
|
||||||
contact: response.contact,
|
contact: response.contact,
|
||||||
contactAttributes: response.contactAttributes,
|
contactAttributes: response.contactAttributes,
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user