Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(atomic): migrate atomic-commerce-sort-dropdown #5078

Draft
wants to merge 15 commits into
base: KIT-3948
Choose a base branch
from
Prev Previous commit
Next Next commit
UT done
y-lakhdar committed Mar 14, 2025

Verified

This commit was signed with the committer’s verified signature.
y-lakhdar ylakhdar
commit 356e850b42c7ca9fab63238d8c697678d65b03db
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {fixture} from '@/vitest-utils/testing-helpers/fixture';
import {createTestI18n} from '@/vitest-utils/testing-helpers/i18n-utils';
import {
import type {
ProductListingState,
SortState,
SearchState,
@@ -10,40 +10,43 @@ import '@vitest/browser/matchers.d.ts';
import {html} from 'lit';
import {describe, test, vi, expect} from 'vitest';
import {CommerceBindings} from '../atomic-commerce-interface/atomic-commerce-interface';
import {AtomicCommerceSortDropdown} from './atomic-commerce-sort-dropdown';
import type {AtomicCommerceSortDropdown} from './atomic-commerce-sort-dropdown';
import './atomic-commerce-sort-dropdown';

vi.mock('../../../utils/initialization-lit-stencil-common-utils', () => ({
fetchBindings: vi.fn().mockImplementation(async () => {
const i18nTest = await createTestI18n();
return new Promise((resolve) => {
resolve({
i18n: i18nTest,

store: {
state: {
iconAssetsPath: './assets',
},
},

interfaceElement: {
type: 'product-listing',
} as HTMLAtomicCommerceInterfaceElement,
} as CommerceBindings);
});
}),
}));

vi.mock('@coveo/headless/commerce', () => {
return {
buildProductListing: vi.fn(() => {
return {
sort: vi.fn(() => ({
sortBy: vi.fn(),
isSortedBy: vi.fn(),
})),
};
}),
buildSearch: vi.fn(() => {
return {
sort: vi.fn(() => ({
sortBy: vi.fn(),
isSortedBy: vi.fn(),
})),
};
}),
buildSearch: vi.fn(),
};
});

async function mockedBindings(element: AtomicCommerceSortDropdown) {
const i18nTest = await createTestI18n();
element.bindings = {
i18n: i18nTest,
interfaceElement: {
type: 'product-listing',
} as HTMLAtomicCommerceInterfaceElement,
} as CommerceBindings;
}

describe('AtomicCommerceSortDropdown', () => {
const locators = {
get label() {
@@ -57,7 +60,6 @@ describe('AtomicCommerceSortDropdown', () => {
},
};

// TODO: add argument to mock state
const setupElement = async ({
mockSearchOrListingState,
mockSortState,
@@ -71,8 +73,6 @@ describe('AtomicCommerceSortDropdown', () => {
html`<atomic-commerce-sort-dropdown></atomic-commerce-sort-dropdown>`
);

console.log('mock state ---');
// TODO: mock to mock folder
element.searchOrListingState = {
responseId: 'some-id',
products: [{}],
@@ -83,20 +83,18 @@ describe('AtomicCommerceSortDropdown', () => {

element.sortState = {
availableSorts: [
{by: 'fields', fields: [{name: 'Price'}]},
{by: 'fields', fields: [{name: 'Something'}]},
{by: 'fields', fields: [{name: 'foo'}]},
{by: 'fields', fields: [{name: 'bar'}]},
],
...mockSortState,
} as SortState;

await mockedBindings(element);
element.initialize();

return element;
};

test('renders label and dropdown correctly', async () => {
await setupElement();
const element = await setupElement();
await element.updateComplete;

await expect.element(locators.label).toBeInTheDocument();
await expect.element(locators.select).toBeInTheDocument();
@@ -132,7 +130,10 @@ describe('AtomicCommerceSortDropdown', () => {
mockSearchOrListingState: {responseId: ''},
});

await expect.element(locators.placeholder(element)).toBeInTheDocument();
const placeholder = () => locators.placeholder(element);
await vi.waitUntil(placeholder);

await expect.element(placeholder()).toBeInTheDocument();
await expect.element(locators.select).not.toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -70,7 +70,6 @@ export class AtomicCommerceSortDropdown
this.searchOrListing = buildSearch(this.bindings.engine);
}
this.sort = this.searchOrListing.sort();
console.log('INIT ---', this.sort);
}

private select(e: Event) {
@@ -98,7 +97,6 @@ export class AtomicCommerceSortDropdown
id,
onSelect: (evt: Event) => this.select(evt),
children: html`${guard([this.sortState], () => {
console.log('SORT ---', this.sort);
return map(this.sortState.availableSorts, (sort) =>
renderCommerceSortOption({
i18n,
@@ -119,7 +117,6 @@ export class AtomicCommerceSortDropdown
@errorGuard()
@bindingGuard()
render() {
console.log('++++' + this.sort);
const {responseId, error, products, isLoading} = this.searchOrListingState!;
return html`${sortGuard(
{
11 changes: 0 additions & 11 deletions packages/atomic/vitest-utils/setup.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import {LitElement} from 'lit';
import {vi} from 'vitest';
import {afterEach} from 'vitest';
import '../src/themes/coveo.css';
@@ -7,20 +6,10 @@ import '../src/utils/tailwind-utilities/utilities.tw.css';
import '../src/utils/tailwind.global.tw.css';
import {fixtureCleanup} from './testing-helpers/fixture-wrapper';

vi.mock('../src/components/common/interface/store', () => ({
createAppLoadedListener: vi.fn(),
}));

vi.mock('../src/decorators/bind-state', () => ({
bindStateToController: vi.fn(),
}));

vi.mock('../src/mixins/bindings-mixin', () => ({
InitializeBindingsMixin: (superClass: typeof LitElement) =>
class extends superClass {},
BindingController: class {},
}));

afterEach(async () => {
fixtureCleanup();
});
32 changes: 32 additions & 0 deletions packages/atomic/vitest.config.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,27 @@
import {readFileSync} from 'fs';
import path from 'node:path';
import {dirname, resolve} from 'path';
import {defineConfig} from 'vitest/config';

const port = 63315;
const resourceUrl = `http://localhost:${port}/`;

/**
* Custom SVG transformer to handle .svg imports.
*/
function svgTransform(code, id) {
return code.replace(
/import\s+([a-zA-Z]+)\s+from\s+['"]([^'"]+\.svg)['"]/g,
(_, importName, importPath) => {
const svgContent = readFileSync(
resolve(dirname(id), importPath),
'utf8'
).replace(/'/g, "\\'");
return `const ${importName} = '${svgContent}';`;
}
);
}

export default defineConfig({
define: {
'import.meta.env.RESOURCE_URL': `"${resourceUrl}"`,
@@ -34,6 +52,20 @@ export default defineConfig({
return null;
},
},
{
name: 'svg-transform',
enforce: 'pre',
transform(code, id) {
if (id.endsWith('.ts')) {
const transformedCode = svgTransform(code, id);
return {
code: transformedCode,
map: null,
};
}
return null;
},
},
],
test: {
include: ['src/**/*.spec.ts'],