307 lines
9.5 KiB
JavaScript
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");
|
|
});
|
|
});
|