Files
pleno-vue/tests/unit/customer-search-field-pos.spec.js
T

307 lines
9.5 KiB
JavaScript

// @vitest-environment jsdom
import { nextTick, ref } from "vue";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { mountWithApp } from "./helpers/mountWithApp.js";
const posState = vi.hoisted(() => ({
customerId: null,
customerName: null,
selectCustomer: vi.fn(),
searchAndSelectCustomer: vi.fn(),
}));
const searchState = vi.hoisted(() => ({
isSearching: null,
results: null,
}));
const draftState = vi.hoisted(() => ({
draftCustomerNumber: null,
hasDraft: null,
}));
const stripeState = vi.hoisted(() => ({
isCardPaymentAvailable: null,
}));
const sessionUserState = vi.hoisted(() => ({
request: vi.fn(),
parseErrorMessage: vi.fn((error) => error?.message ?? null),
}));
vi.mock("@/components/shop/POSDepartmentProcess.vue", async () => {
posState.customerId = ref(null);
posState.customerName = ref("");
posState.selectCustomer.mockImplementation((customer) => {
posState.customerId.value = customer?.customerNumber ?? null;
posState.customerName.value = customer?.name ?? "";
});
posState.searchAndSelectCustomer.mockImplementation(async (customerNumber) => {
const selectedCustomer = {
customerNumber: Number(customerNumber),
name: `Customer ${customerNumber}`,
};
posState.selectCustomer(selectedCustomer);
return selectedCustomer;
});
return {
customer_id: posState.customerId,
customer_name: posState.customerName,
isCustomerBarred: vi.fn(() => false),
selectCustomer: posState.selectCustomer,
isCustomerSelected: () => Boolean(posState.customerId.value),
searchAndSelectCustomer: posState.searchAndSelectCustomer,
};
});
vi.mock("@/components/search/economic/customerSearch.vue", async () => {
searchState.isSearching = ref(false);
searchState.results = ref([]);
return {
isSearching: searchState.isSearching,
searchCustomerResults: searchState.results,
};
});
vi.mock("@/components/session/token/SessionUser.vue", () => {
const sessionUser = {
request: sessionUserState.request,
functions: {
parseErrorMessage: sessionUserState.parseErrorMessage,
},
objects: {
global: {
language: {
customer: "Kunde",
clear: "Clear",
},
},
},
};
return {
SessionUser: sessionUser,
default: sessionUser,
};
});
vi.mock("@/composables/useDraftTransactionCustomer.js", () => ({
useDraftTransactionCustomer: () => ({
draftTransactionCustomerNumber: draftState.draftCustomerNumber,
hasDraftTransactionCustomer: draftState.hasDraft,
}),
}));
vi.mock("@/composables/useStripeReaderAvailability.js", () => ({
useStripeReaderAvailability: () => ({
isCardPaymentAvailable: stripeState.isCardPaymentAvailable,
}),
}));
import CustomerSearchFieldPos from "@/components/forms/department/pos/input/customerSearchFieldPos.vue";
const CustomerSearchFieldStub = {
name: "CustomerSearchField",
template: '<input v-bind="$attrs" />',
};
async function flushComponentUpdates() {
await Promise.resolve();
await nextTick();
}
function mountComponent(props = {}) {
return mountWithApp(CustomerSearchFieldPos, {
props,
messages: {
en: {
pos: {
customer_picker: {
selected_customer: "Selected customer",
select_customer_invoice: "Customer invoice",
select_new_customer: "New customer",
select_draft_customer: "Defer",
select_card_payment: "Payment card",
},
},
admin: {
pos: {
company_phone: "Company phone",
invoice_email: "Invoice email",
contact_email: "Contact email",
contact_phone: "Contact phone",
ean: "EAN",
add_customer: "Add customer",
customer_creation_error: "Error: {error}",
customer_creation_error_generic: "Unable to create customer",
not_found: "Not found",
},
},
global: {
search_cvr: "Search CVR",
},
common: {
cancel: "Cancel",
},
},
},
global: {
stubs: {
CustomerSearchField: CustomerSearchFieldStub,
"customer-search-field": CustomerSearchFieldStub,
},
},
});
}
describe("CustomerSearchFieldPos", () => {
beforeEach(() => {
vi.useFakeTimers();
posState.customerId.value = null;
posState.customerName.value = "";
posState.selectCustomer.mockClear();
posState.searchAndSelectCustomer.mockClear();
searchState.isSearching.value = false;
searchState.results.value = [];
draftState.draftCustomerNumber = ref(6001);
draftState.hasDraft = ref(true);
stripeState.isCardPaymentAvailable = ref(true);
sessionUserState.request.mockReset();
sessionUserState.parseErrorMessage.mockClear();
});
afterEach(() => {
vi.runOnlyPendingTimers();
vi.useRealTimers();
});
it("shows the inline Ny kunde form and hides manual search while the mode is active", async () => {
const wrapper = mountComponent();
expect(wrapper.find("#pos_select_customer_input").exists()).toBe(true);
await wrapper.get('[data-testid="pos-new-customer-inline-action"]').trigger("click");
await nextTick();
expect(wrapper.find("#pos_select_customer_input").exists()).toBe(false);
expect(wrapper.find('[data-testid="pos-desktop-add-customer-inline-form"]').exists()).toBe(true);
});
it("resets the inline add-customer form when the operator cancels out of Ny kunde mode", async () => {
sessionUserState.request.mockImplementation(async (path) => {
if (path === "/cvr/search") {
return {
data: {
data: {
vat: 41004355,
name: "Truckwash ApS",
phone: "21754690",
email: "mikkel@truckwash.dk",
},
},
};
}
throw new Error(`Unexpected request: ${path}`);
});
const wrapper = mountComponent();
await wrapper.get('[data-testid="pos-new-customer-inline-action"]').trigger("click");
await wrapper.get('[data-testid="pos-desktop-add-customer-search-input"]').setValue("41004355");
await vi.advanceTimersByTimeAsync(300);
await flushComponentUpdates();
expect(wrapper.get('[data-testid="pos-desktop-add-customer-company-phone"]').element.value).toBe("21754690");
await wrapper.get('[data-testid="pos-desktop-add-customer-cancel"]').trigger("click");
await nextTick();
expect(wrapper.find('[data-testid="pos-desktop-add-customer-inline-form"]').exists()).toBe(false);
expect(wrapper.find("#pos_select_customer_input").exists()).toBe(true);
await wrapper.get('[data-testid="pos-new-customer-inline-action"]').trigger("click");
await nextTick();
expect(wrapper.get('[data-testid="pos-desktop-add-customer-search-input"]').element.value).toBe("");
expect(wrapper.get('[data-testid="pos-desktop-add-customer-company-phone"]').element.value).toBe("");
});
it("submits a new customer inline and emits the selected customer after creation", async () => {
sessionUserState.request.mockImplementation(async (path, method, payload) => {
if (path === "/cvr/search") {
return {
data: {
data: {
vat: 43423010,
name: "Wash Group ApS",
phone: "42331128",
email: "billing@wash-group.test",
},
},
};
}
if (path === "/auth/register/cvr") {
expect(method).toBe("POST");
expect(payload).toMatchObject({
cvr: "43423010",
companyPhone: 55550000,
invoiceEmail: "billing@wash-group.test",
contactEmail: "dispatch@wash-group.test",
contactPhone: 42331128,
ean: "5790001234567",
});
return {
data: {
data: {
success: true,
},
},
};
}
throw new Error(`Unexpected request: ${path}`);
});
posState.searchAndSelectCustomer.mockImplementation(async (customerNumber) => {
const selectedCustomer = {
customerNumber: Number(customerNumber),
name: "Wash Group ApS",
};
posState.selectCustomer(selectedCustomer);
return selectedCustomer;
});
const onCustomerSelected = vi.fn();
const wrapper = mountComponent({ onCustomerSelected });
await wrapper.get('[data-testid="pos-new-customer-inline-action"]').trigger("click");
await wrapper.get('[data-testid="pos-desktop-add-customer-search-input"]').setValue("43423010");
await vi.advanceTimersByTimeAsync(300);
await flushComponentUpdates();
await wrapper.get('[data-testid="pos-desktop-add-customer-company-phone"]').setValue("55550000");
await wrapper.get('[data-testid="pos-desktop-add-customer-contact-email"]').setValue("dispatch@wash-group.test");
await wrapper.get('[data-testid="pos-desktop-add-customer-ean"]').setValue("5790001234567");
await wrapper.get('[data-testid="pos-desktop-add-customer-submit"]').trigger("click");
await flushComponentUpdates();
expect(posState.searchAndSelectCustomer).toHaveBeenCalledWith("55550000");
expect(onCustomerSelected).toHaveBeenCalledWith(
expect.objectContaining({
customerNumber: 55550000,
name: "Wash Group ApS",
})
);
expect(wrapper.find('[data-testid="pos-desktop-add-customer-inline-form"]').exists()).toBe(false);
expect(wrapper.get('button[data-testid="pos-customer-invoice-inline-action"]').classes()).toContain("is-selected");
expect(wrapper.get("input[disabled]").element.value).toBe("Wash Group ApS");
});
});