





















@@ -120,6 +120,54 @@ function plan(items: MigrationItem[]): MigrationPlan {
120120};
121121}
122122123+function expectSummaryFields(
124+summary: MigrationPlan["summary"],
125+fields: Partial<MigrationPlan["summary"]>,
126+) {
127+for (const [key, value] of Object.entries(fields)) {
128+expect(summary[key as keyof MigrationPlan["summary"]]).toBe(value);
129+}
130+}
131+132+function requireItem(items: MigrationItem[], id: string): MigrationItem {
133+const item = items.find((candidate) => candidate.id === id);
134+expect(item).toBeDefined();
135+if (!item) {
136+throw new Error(`missing migration item ${id}`);
137+}
138+return item;
139+}
140+141+function expectItemStatus(
142+items: MigrationItem[],
143+id: string,
144+status: MigrationItem["status"],
145+reason?: string,
146+) {
147+const item = requireItem(items, id);
148+expect(item.status).toBe(status);
149+if (reason !== undefined) {
150+expect(item.reason).toBe(reason);
151+}
152+}
153+154+function requireRecord(value: unknown, label: string): Record<string, unknown> {
155+expect(typeof value).toBe("object");
156+expect(value).not.toBeNull();
157+if (typeof value !== "object" || value === null) {
158+throw new Error(`${label} was not an object`);
159+}
160+return value as Record<string, unknown>;
161+}
162+163+function requireCodexPluginConfigPlugins(item: MigrationItem): Record<string, unknown> {
164+const details = requireRecord(item.details, "config details");
165+const value = requireRecord(details.value, "config value");
166+const config = requireRecord(value.config, "config object");
167+const codexPlugins = requireRecord(config.codexPlugins, "codex plugin config");
168+return requireRecord(codexPlugins.plugins, "configured plugins");
169+}
170+123171describe("applyMigrationSkillSelection", () => {
124172it("keeps selected skills and skips unselected skill copy items", () => {
125173const selected = applyMigrationSkillSelection(
@@ -142,23 +190,15 @@ describe("applyMigrationSkillSelection", () => {
142190["alpha"],
143191);
144192145-expect(selected.summary).toMatchObject({
193+expectSummaryFields(selected.summary, {
146194total: 4,
147195planned: 2,
148196skipped: 2,
149197conflicts: 0,
150198});
151-expect(selected.items).toEqual(
152-expect.arrayContaining([
153-expect.objectContaining({ id: "skill:alpha", status: "planned" }),
154-expect.objectContaining({
155-id: "skill:beta",
156-status: "skipped",
157-reason: MIGRATION_SKILL_NOT_SELECTED_REASON,
158-}),
159-expect.objectContaining({ id: "archive:config.toml", status: "planned" }),
160-]),
161-);
199+expectItemStatus(selected.items, "skill:alpha", "planned");
200+expectItemStatus(selected.items, "skill:beta", "skipped", MIGRATION_SKILL_NOT_SELECTED_REASON);
201+expectItemStatus(selected.items, "archive:config.toml", "planned");
162202});
163203164204it("accepts item ids as non-interactive skill selectors", () => {
@@ -167,9 +207,8 @@ describe("applyMigrationSkillSelection", () => {
167207["skill:alpha"],
168208);
169209170-expect(selected.items).toEqual([
171-expect.objectContaining({ id: "skill:alpha", status: "planned" }),
172-]);
210+expect(selected.items).toHaveLength(1);
211+expectItemStatus(selected.items, "skill:alpha", "planned");
173212});
174213175214it("can skip conflicting skills before apply conflict checks run", () => {
@@ -187,16 +226,8 @@ describe("applyMigrationSkillSelection", () => {
187226);
188227189228expect(selected.summary.conflicts).toBe(0);
190-expect(selected.items).toEqual(
191-expect.arrayContaining([
192-expect.objectContaining({ id: "skill:alpha", status: "planned" }),
193-expect.objectContaining({
194-id: "skill:beta",
195-status: "skipped",
196-reason: MIGRATION_SKILL_NOT_SELECTED_REASON,
197-}),
198-]),
199-);
229+expectItemStatus(selected.items, "skill:alpha", "planned");
230+expectItemStatus(selected.items, "skill:beta", "skipped", MIGRATION_SKILL_NOT_SELECTED_REASON);
200231});
201232202233it("allows interactive selection to choose no skills", () => {
@@ -208,7 +239,7 @@ describe("applyMigrationSkillSelection", () => {
208239new Set(),
209240);
210241211-expect(selected.summary).toMatchObject({ planned: 0, skipped: 2 });
242+expectSummaryFields(selected.summary, { planned: 0, skipped: 2 });
212243expect(selected.items.map((item) => item.status)).toEqual(["skipped", "skipped"]);
213244});
214245@@ -381,45 +412,23 @@ describe("applyMigrationPluginSelection", () => {
381412["google-calendar"],
382413);
383414384-expect(selected.summary).toMatchObject({ planned: 2, skipped: 1, conflicts: 0 });
385-expect(selected.items).toEqual(
386-expect.arrayContaining([
387-expect.objectContaining({ id: "plugin:google-calendar", status: "planned" }),
388-expect.objectContaining({
389-id: "plugin:gmail",
390-status: "skipped",
391-reason: MIGRATION_PLUGIN_NOT_SELECTED_REASON,
392-}),
393-expect.objectContaining({ id: "config:codex-plugins", status: "planned" }),
394-]),
415+expectSummaryFields(selected.summary, { planned: 2, skipped: 1, conflicts: 0 });
416+expectItemStatus(selected.items, "plugin:google-calendar", "planned");
417+expectItemStatus(
418+selected.items,
419+"plugin:gmail",
420+"skipped",
421+MIGRATION_PLUGIN_NOT_SELECTED_REASON,
395422);
396-expect(
397-selected.items.find((item) => item.id === "config:codex-plugins")?.details?.value,
398-).toMatchObject({
399-config: {
400-codexPlugins: {
401-plugins: {
402-"google-calendar": {
403-enabled: true,
404-marketplaceName: "openai-curated",
405-pluginName: "google-calendar",
406-},
407-},
408-},
409-},
423+const configItem = requireItem(selected.items, "config:codex-plugins");
424+expect(configItem.status).toBe("planned");
425+const plugins = requireCodexPluginConfigPlugins(configItem);
426+expect(requireRecord(plugins["google-calendar"], "google calendar plugin config")).toEqual({
427+enabled: true,
428+marketplaceName: "openai-curated",
429+pluginName: "google-calendar",
410430});
411-expect(
412-Object.keys(
413-(
414-(
415-(
416-selected.items.find((item) => item.id === "config:codex-plugins")?.details
417-?.value as Record<string, unknown>
418-).config as Record<string, unknown>
419-).codexPlugins as Record<string, unknown>
420-).plugins as Record<string, unknown>,
421-),
422-).toEqual(["google-calendar"]);
431+expect(Object.keys(plugins)).toEqual(["google-calendar"]);
423432});
424433425434it("skips the Codex plugin config item when no plugin remains selected", () => {
@@ -432,25 +441,24 @@ describe("applyMigrationPluginSelection", () => {
432441[],
433442);
434443435-expect(selected.summary).toMatchObject({ planned: 0, skipped: 3, conflicts: 0 });
436-expect(selected.items).toEqual(
437-expect.arrayContaining([
438-expect.objectContaining({
439-id: "plugin:google-calendar",
440-status: "skipped",
441-reason: MIGRATION_PLUGIN_NOT_SELECTED_REASON,
442-}),
443-expect.objectContaining({
444-id: "plugin:gmail",
445-status: "skipped",
446-reason: MIGRATION_PLUGIN_NOT_SELECTED_REASON,
447-}),
448-expect.objectContaining({
449-id: "config:codex-plugins",
450-status: "skipped",
451-reason: MIGRATION_PLUGIN_NOT_SELECTED_REASON,
452-}),
453-]),
444+expectSummaryFields(selected.summary, { planned: 0, skipped: 3, conflicts: 0 });
445+expectItemStatus(
446+selected.items,
447+"plugin:google-calendar",
448+"skipped",
449+MIGRATION_PLUGIN_NOT_SELECTED_REASON,
450+);
451+expectItemStatus(
452+selected.items,
453+"plugin:gmail",
454+"skipped",
455+MIGRATION_PLUGIN_NOT_SELECTED_REASON,
456+);
457+expectItemStatus(
458+selected.items,
459+"config:codex-plugins",
460+"skipped",
461+MIGRATION_PLUGIN_NOT_SELECTED_REASON,
454462);
455463});
456464@@ -464,7 +472,7 @@ describe("applyMigrationPluginSelection", () => {
464472new Set(),
465473);
466474467-expect(selected.summary).toMatchObject({ planned: 0, skipped: 3 });
475+expectSummaryFields(selected.summary, { planned: 0, skipped: 3 });
468476expect(selected.items.every((item) => item.status === "skipped")).toBe(true);
469477});
470478@@ -532,9 +540,8 @@ describe("applyMigrationPluginSelection", () => {
532540["plugin:google-calendar"],
533541);
534542535-expect(selected.items).toEqual([
536-expect.objectContaining({ id: "plugin:google-calendar", status: "planned" }),
537-]);
543+expect(selected.items).toHaveLength(1);
544+expectItemStatus(selected.items, "plugin:google-calendar", "planned");
538545});
539546540547it("rejects unknown explicit plugin selectors with available choices", () => {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。