feat(category): 类目树、属性、属性字典维护,新增系统管理员管理类目数据
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { test } from 'node:test';
|
||||
import { fetchOzonDictionaryBatch, fetchOzonDictionaryValues } from '../src/ozon-client.ts';
|
||||
|
||||
const input = {
|
||||
attributeId: '123',
|
||||
categoryId: '456',
|
||||
typeId: '789',
|
||||
};
|
||||
|
||||
test('属性字典按 Ozon 游标读取多页', async () => {
|
||||
const previousFetch = globalThis.fetch;
|
||||
const requests = [];
|
||||
globalThis.fetch = async (url, options) => {
|
||||
requests.push({ url, body: JSON.parse(options.body) });
|
||||
const data = requests.length === 1
|
||||
? { result: [{ id: 1, value: '中国' }], has_next: true }
|
||||
: { result: [{ id: 2, value: '法国' }], has_next: false };
|
||||
return new Response(JSON.stringify(data), { status: 200 });
|
||||
};
|
||||
try {
|
||||
const values = await fetchOzonDictionaryValues('client', 'key', input);
|
||||
assert.deepEqual(values.map((value) => value.value), ['中国', '法国']);
|
||||
assert.equal(requests.length, 2);
|
||||
assert.equal(requests[0].body.last_value_id, 0);
|
||||
assert.equal(requests[1].body.last_value_id, 1);
|
||||
assert.ok(requests.every((request) => request.url.endsWith('/attribute/values')));
|
||||
} finally {
|
||||
globalThis.fetch = previousFetch;
|
||||
}
|
||||
});
|
||||
|
||||
test('关键词使用 Ozon 字典搜索接口', async () => {
|
||||
const previousFetch = globalThis.fetch;
|
||||
const requests = [];
|
||||
globalThis.fetch = async (url, options) => {
|
||||
requests.push({ url, body: JSON.parse(options.body) });
|
||||
return new Response(JSON.stringify({ result: [{ id: 3, value: '儿童' }] }), {
|
||||
status: 200,
|
||||
});
|
||||
};
|
||||
try {
|
||||
const values = await fetchOzonDictionaryValues('client', 'key', {
|
||||
...input,
|
||||
query: '儿童',
|
||||
});
|
||||
assert.equal(values.length, 1);
|
||||
assert.equal(requests.length, 1);
|
||||
assert.ok(requests[0].url.endsWith('/attribute/values/search'));
|
||||
assert.equal(requests[0].body.value, '儿童');
|
||||
} finally {
|
||||
globalThis.fetch = previousFetch;
|
||||
}
|
||||
});
|
||||
|
||||
test('Ozon 返回重复游标时停止翻页', async () => {
|
||||
const previousFetch = globalThis.fetch;
|
||||
let calls = 0;
|
||||
globalThis.fetch = async () => {
|
||||
calls += 1;
|
||||
return new Response(JSON.stringify({
|
||||
result: [{ id: 1, value: '中国' }],
|
||||
has_next: true,
|
||||
}), { status: 200 });
|
||||
};
|
||||
try {
|
||||
const values = await fetchOzonDictionaryValues('client', 'key', input);
|
||||
assert.equal(values.length, 1);
|
||||
assert.equal(calls, 2);
|
||||
} finally {
|
||||
globalThis.fetch = previousFetch;
|
||||
}
|
||||
});
|
||||
|
||||
test('平台字典批量同步会报告分页是否完整', async () => {
|
||||
const previousFetch = globalThis.fetch;
|
||||
const requests = [];
|
||||
globalThis.fetch = async (_url, options) => {
|
||||
requests.push(JSON.parse(options.body));
|
||||
const page = requests.length;
|
||||
return new Response(JSON.stringify({
|
||||
result: [{ id: page, value: `候选值 ${page}` }],
|
||||
has_next: page < 2,
|
||||
}), { status: 200 });
|
||||
};
|
||||
try {
|
||||
const batch = await fetchOzonDictionaryBatch('client', 'key', input);
|
||||
assert.equal(batch.isComplete, true);
|
||||
assert.deepEqual(batch.values.map((value) => value.id), [1, 2]);
|
||||
assert.equal(requests[0].limit, 2000);
|
||||
assert.equal(requests[1].last_value_id, 1);
|
||||
} finally {
|
||||
globalThis.fetch = previousFetch;
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,53 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { test } from 'node:test';
|
||||
import {
|
||||
flattenPlatformCategories,
|
||||
mapPlatformAttributes,
|
||||
} from '../src/platform-catalog-mappers.ts';
|
||||
|
||||
test('类目树叶子继承 description_category_id 并保留 type_id', () => {
|
||||
const rows = flattenPlatformCategories([{
|
||||
description_category_id: 17027922,
|
||||
category_name: '儿童玩具',
|
||||
children: [{ type_id: 8229, type_name: '玩具类型' }],
|
||||
}]);
|
||||
|
||||
assert.equal(rows.length, 2);
|
||||
assert.deepEqual(rows.map((row) => [row.external_category_id, row.external_type_id]), [
|
||||
['17027922', '0'],
|
||||
['17027922', '8229'],
|
||||
]);
|
||||
assert.equal(rows[1].parent_key, '17027922:0');
|
||||
assert.equal(rows[1].path, '儿童玩具 › 玩具类型');
|
||||
assert.equal(rows[1].is_active, true);
|
||||
});
|
||||
|
||||
test('属性定义按 Ozon 属性 ID 和 complex ID 去重并保留约束', () => {
|
||||
const rows = mapPlatformAttributes([{
|
||||
id: 85,
|
||||
attribute_complex_id: 0,
|
||||
name: '品牌',
|
||||
type: 'String',
|
||||
dictionary_id: 321,
|
||||
is_required: true,
|
||||
is_collection: true,
|
||||
max_value_count: 1000,
|
||||
category_dependent: false,
|
||||
}, {
|
||||
id: 85,
|
||||
attribute_complex_id: 0,
|
||||
name: '品牌(更新)',
|
||||
type: 'String',
|
||||
dictionary_id: 321,
|
||||
is_required: true,
|
||||
is_collection: true,
|
||||
max_value_count: 2,
|
||||
}]);
|
||||
|
||||
assert.equal(rows.length, 1);
|
||||
assert.equal(rows[0].platform_attribute_id, '85');
|
||||
assert.equal(rows[0].complex_id, '0');
|
||||
assert.equal(rows[0].value_type, 'dictionary');
|
||||
assert.equal(rows[0].max_value_count, 2);
|
||||
assert.equal(rows[0].name, '品牌(更新)');
|
||||
});
|
||||
Reference in New Issue
Block a user