@prenta/admin 1.13.0 → 1.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/dist/__tests__/lib/api.test.d.ts +2 -0
- package/dist/__tests__/lib/api.test.d.ts.map +1 -0
- package/dist/__tests__/lib/api.test.js +58 -0
- package/dist/__tests__/lib/api.test.js.map +1 -0
- package/dist/__tests__/lib/seo-service-autopilot.test.d.ts +2 -0
- package/dist/__tests__/lib/seo-service-autopilot.test.d.ts.map +1 -0
- package/dist/__tests__/lib/seo-service-autopilot.test.js +171 -0
- package/dist/__tests__/lib/seo-service-autopilot.test.js.map +1 -0
- package/dist/__tests__/lib/seo-service-proposals.test.d.ts +2 -0
- package/dist/__tests__/lib/seo-service-proposals.test.d.ts.map +1 -0
- package/dist/__tests__/lib/seo-service-proposals.test.js +99 -0
- package/dist/__tests__/lib/seo-service-proposals.test.js.map +1 -0
- package/dist/__tests__/router/seo-tab-for-path.test.js +1 -0
- package/dist/__tests__/router/seo-tab-for-path.test.js.map +1 -1
- package/dist/__tests__/views/redirects-pane.render.test.js +30 -12
- package/dist/__tests__/views/redirects-pane.render.test.js.map +1 -1
- package/dist/__tests__/views/seo-autopilot-applied.render.test.d.ts +2 -0
- package/dist/__tests__/views/seo-autopilot-applied.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/seo-autopilot-applied.render.test.js +330 -0
- package/dist/__tests__/views/seo-autopilot-applied.render.test.js.map +1 -0
- package/dist/__tests__/views/seo-autopilot-card.render.test.d.ts +2 -0
- package/dist/__tests__/views/seo-autopilot-card.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/seo-autopilot-card.render.test.js +512 -0
- package/dist/__tests__/views/seo-autopilot-card.render.test.js.map +1 -0
- package/dist/__tests__/views/seo-proposals-tab.render.test.d.ts +2 -0
- package/dist/__tests__/views/seo-proposals-tab.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/seo-proposals-tab.render.test.js +431 -0
- package/dist/__tests__/views/seo-proposals-tab.render.test.js.map +1 -0
- package/dist/__tests__/views/seo-settings.render.test.js +41 -4
- package/dist/__tests__/views/seo-settings.render.test.js.map +1 -1
- package/dist/components/seo/ChangePreview.d.ts +6 -0
- package/dist/components/seo/ChangePreview.d.ts.map +1 -0
- package/dist/components/seo/ChangePreview.js +18 -0
- package/dist/components/seo/ChangePreview.js.map +1 -0
- package/dist/components/seo/SeoIssueFixPanel.d.ts.map +1 -1
- package/dist/components/seo/SeoIssueFixPanel.js +1 -14
- package/dist/components/seo/SeoIssueFixPanel.js.map +1 -1
- package/dist/lib/api.d.ts +13 -2
- package/dist/lib/api.d.ts.map +1 -1
- package/dist/lib/api.js +1 -2
- package/dist/lib/api.js.map +1 -1
- package/dist/lib/seo-service.d.ts +293 -2
- package/dist/lib/seo-service.d.ts.map +1 -1
- package/dist/lib/seo-service.js +170 -0
- package/dist/lib/seo-service.js.map +1 -1
- package/dist/prenta-admin.css +1 -1
- package/dist/views/SEO.d.ts +5 -1
- package/dist/views/SEO.d.ts.map +1 -1
- package/dist/views/SEO.js +28 -9
- package/dist/views/SEO.js.map +1 -1
- package/dist/views/seo/AutopilotAppliedSection.d.ts +10 -0
- package/dist/views/seo/AutopilotAppliedSection.d.ts.map +1 -0
- package/dist/views/seo/AutopilotAppliedSection.js +295 -0
- package/dist/views/seo/AutopilotAppliedSection.js.map +1 -0
- package/dist/views/seo/ProposalsTab.d.ts +7 -0
- package/dist/views/seo/ProposalsTab.d.ts.map +1 -0
- package/dist/views/seo/ProposalsTab.js +334 -0
- package/dist/views/seo/ProposalsTab.js.map +1 -0
- package/dist/views/seo/RedirectsTab.d.ts +3 -1
- package/dist/views/seo/RedirectsTab.d.ts.map +1 -1
- package/dist/views/seo/RedirectsTab.js +14 -19
- package/dist/views/seo/RedirectsTab.js.map +1 -1
- package/dist/views/seo/relative-age.d.ts +7 -0
- package/dist/views/seo/relative-age.d.ts.map +1 -0
- package/dist/views/seo/relative-age.js +20 -0
- package/dist/views/seo/relative-age.js.map +1 -0
- package/dist/views/settings/SeoAutopilotCard.d.ts +30 -0
- package/dist/views/settings/SeoAutopilotCard.d.ts.map +1 -0
- package/dist/views/settings/SeoAutopilotCard.js +375 -0
- package/dist/views/settings/SeoAutopilotCard.js.map +1 -0
- package/dist/views/settings/SeoSettingsTab.d.ts.map +1 -1
- package/dist/views/settings/SeoSettingsTab.js +2 -1
- package/dist/views/settings/SeoSettingsTab.js.map +1 -1
- package/dist/views/settings/components.d.ts +3 -1
- package/dist/views/settings/components.d.ts.map +1 -1
- package/dist/views/settings/components.js +2 -2
- package/dist/views/settings/components.js.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/lib/api.test.ts +76 -0
- package/src/__tests__/lib/seo-service-autopilot.test.ts +196 -0
- package/src/__tests__/lib/seo-service-proposals.test.ts +108 -0
- package/src/__tests__/router/seo-tab-for-path.test.ts +1 -0
- package/src/__tests__/views/redirects-pane.render.test.tsx +36 -16
- package/src/__tests__/views/seo-autopilot-applied.render.test.tsx +382 -0
- package/src/__tests__/views/seo-autopilot-card.render.test.tsx +610 -0
- package/src/__tests__/views/seo-proposals-tab.render.test.tsx +531 -0
- package/src/__tests__/views/seo-settings.render.test.tsx +47 -7
- package/src/components/seo/ChangePreview.tsx +47 -0
- package/src/components/seo/SeoIssueFixPanel.tsx +1 -44
- package/src/lib/api.ts +19 -3
- package/src/lib/seo-service.ts +455 -2
- package/src/views/SEO.tsx +41 -8
- package/src/views/seo/AutopilotAppliedSection.tsx +597 -0
- package/src/views/seo/ProposalsTab.tsx +761 -0
- package/src/views/seo/RedirectsTab.tsx +39 -60
- package/src/views/seo/relative-age.ts +15 -0
- package/src/views/settings/SeoAutopilotCard.tsx +826 -0
- package/src/views/settings/SeoSettingsTab.tsx +2 -0
- package/src/views/settings/components.tsx +10 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,36 @@
|
|
|
1
1
|
# @actuate-media/cms-admin
|
|
2
2
|
|
|
3
|
+
## 1.15.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 2f0c3b3: SEO Autopilot (auto-apply policy engine, roadmap item 5).
|
|
8
|
+
- **core**: per-issue-type autopilot policy on `SeoModuleSettings.autopilot`; deterministic gate (brand alignment, banned terms word-bounded, validators, duplicate check, redirect confidence, AI-governance veto, caps, cooldown); new `SeoAutoApply` ledger table (`prenta_seo_auto_applies`, migration `0017_seo_auto_applies`) with field-level before/after and one-call revert; daily `/cron/seo-autopilot` tick (outcome watch → generate → gate → apply → verify → ledger); Search Console outcome watch auto-reverts regressions and pauses the type; routes `GET/PUT /seo/autopilot/settings`, `POST /seo/autopilot/run`, `GET /seo/autopilot/applied`, `POST /seo/autopilot/applied/:id/revert`; digest gains an "Autopilot this week" block. The 404-recovery auto-apply lever is folded into the engine: the stored `redirectRecoveryAutoApply*` fields are deprecated and only ever _read_ — the policy resolver falls back to them per key (`types.redirect`, `redirectMinConfidence`, and `enabled` / `enabledById` when the lever is on) only when the `autopilot` block lacks that key, so explicit autopilot values always win. `GET/PUT /seo/redirects/recovery-settings` keep their wire shape but now read from and write to the autopilot block (never the legacy fields), and `generateRecoverySuggestions` no longer applies redirects itself — `/seo/redirects/suggest` keeps returning `autoApplied: 0` and `governanceBlocked: null` for one release. Existing instances add the `0 6 * * *` `/api/cms/cron/seo-autopilot` cron entry and run `prisma migrate deploy` (un-migrated instances get a self-describing 501 from the autopilot routes).
|
|
9
|
+
- **admin**: Settings → SEO "SEO Autopilot" card; SEO → Proposals "Applied by autopilot" section with Revert (409 conflict → "Revert anyway"); Redirects tab auto-apply controls replaced by a managed-by link.
|
|
10
|
+
- **mcp-server**: `get_seo_autopilot_settings`, `update_seo_autopilot_settings`, `run_seo_autopilot`, `list_seo_autopilot_applied`, `revert_seo_autopilot_change`.
|
|
11
|
+
- **create-prenta**: scaffolded `vercel.json` gains the `0 6 * * *` `/api/cms/cron/seo-autopilot` cron when the SEO plugin is selected; bundled Prisma assets resynced.
|
|
12
|
+
|
|
13
|
+
## 1.14.0
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- 8b6b25c: AI Proposals Inbox (SEO AI roadmap item 4).
|
|
18
|
+
|
|
19
|
+
**@prenta/core**
|
|
20
|
+
- New routes: `GET /seo/proposals` (unified list of cached issue fixes + open 404 redirect suggestions with staleness, brand-alignment, confidence, and per-feature `allowBulkApply` flags), `POST /seo/proposals/generate` (confirm-gated batch generation, 10 issues per call, 3 concurrent, 20 s budget, halts on `rate_limited`), `POST /seo/proposals/bulk-apply` (max 50; >1 items require `allowBulkApply` for every represented feature → 403 `governance_blocked`; same-document items are applied sequentially against a batch-start snapshot; unreached items return `pending`), `POST /seo/issues/:id/dismiss-fix` (sticky dismissal, audited as `seo_fix_dismissed`).
|
|
21
|
+
- `SeoIssue.metadata.pendingFix` now stores `brandAlignment` (minimum across text fields) and `generatedAt`; `dismissedFingerprint` / `generateSkippedFingerprint` markers keep batch generation from recreating rejected or non-cacheable proposals until the document changes.
|
|
22
|
+
- `SuggestIssueFixResult` gains optional `aiError` (code + message) when the AI path refused or failed.
|
|
23
|
+
- `applyIssueFix` (`seo/issue-fix-apply.ts`) and `acceptRedirectSuggestion` (`redirects/suggestion-accept.ts`) are extracted services; the existing routes keep identical HTTP behaviour.
|
|
24
|
+
- `GET /seo/overview` gains `pendingProposals: { issueFixes, redirects }`.
|
|
25
|
+
- New governance helper `assertBulkApplyAllowed`.
|
|
26
|
+
|
|
27
|
+
**@prenta/admin**
|
|
28
|
+
- New SEO → Proposals tab: multi-select, batch approve (disabled with a Settings link when governance forbids bulk apply), batch dismiss, capped "Generate proposals" loop with Stop, stale-row flagging, "Apply remaining" after a time-budget cut-off. `ChangePreview` is now a shared component.
|
|
29
|
+
|
|
30
|
+
**@prenta/mcp-server**
|
|
31
|
+
- New tools: `list_seo_proposals`, `generate_seo_proposals` (confirm-gated), `bulk_apply_seo_proposals` (confirm-gated), `dismiss_seo_proposal`.
|
|
32
|
+
- `PrentaClientError` now carries the server's machine-readable `code` (e.g. `plan_required`, `governance_blocked`) alongside `status`, and tool error responses append it to the error text as `(code: <code>)` so the calling agent can branch on it.
|
|
33
|
+
|
|
3
34
|
## 1.13.0
|
|
4
35
|
|
|
5
36
|
### Minor Changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/lib/api.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// @vitest-environment node
|
|
2
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { cmsApi, getApiBase, setApiBase } from '../../lib/api.js';
|
|
4
|
+
function jsonResponse(status, body) {
|
|
5
|
+
return new Response(JSON.stringify(body), {
|
|
6
|
+
status,
|
|
7
|
+
headers: { 'Content-Type': 'application/json' },
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
const originalBase = getApiBase();
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
vi.unstubAllGlobals();
|
|
13
|
+
setApiBase(originalBase);
|
|
14
|
+
});
|
|
15
|
+
describe('cmsApi', () => {
|
|
16
|
+
it('unwraps a 2xx { data } envelope once and reports the status', async () => {
|
|
17
|
+
const fetchMock = vi.fn(async () => jsonResponse(200, { data: { docs: [], total: 0 } }));
|
|
18
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
19
|
+
await expect(cmsApi('/seo/autopilot/applied?page=1')).resolves.toEqual({
|
|
20
|
+
data: { docs: [], total: 0 },
|
|
21
|
+
status: 200,
|
|
22
|
+
});
|
|
23
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
24
|
+
const [url, init] = fetchMock.mock.calls[0];
|
|
25
|
+
expect(url).toBe('/api/cms/seo/autopilot/applied?page=1');
|
|
26
|
+
expect(init.credentials).toBe('include');
|
|
27
|
+
});
|
|
28
|
+
it('surfaces a non-2xx JSON body as error, code, errorBody, and status', async () => {
|
|
29
|
+
const body = {
|
|
30
|
+
error: 'metaTitle was edited since autopilot changed it',
|
|
31
|
+
code: 'conflict',
|
|
32
|
+
fields: ['metaTitle'],
|
|
33
|
+
};
|
|
34
|
+
vi.stubGlobal('fetch', vi.fn(async () => jsonResponse(409, body)));
|
|
35
|
+
await expect(cmsApi('/seo/autopilot/applied/la-1/revert', { method: 'POST' })).resolves.toEqual({
|
|
36
|
+
error: 'metaTitle was edited since autopilot changed it',
|
|
37
|
+
code: 'conflict',
|
|
38
|
+
errorBody: body,
|
|
39
|
+
status: 409,
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
it('falls back to a generic message and drops a non-string code on a bare non-2xx', async () => {
|
|
43
|
+
vi.stubGlobal('fetch', vi.fn(async () => new Response('not json', { status: 502 })));
|
|
44
|
+
await expect(cmsApi('/anything')).resolves.toEqual({
|
|
45
|
+
error: 'Request failed (502)',
|
|
46
|
+
code: undefined,
|
|
47
|
+
errorBody: {},
|
|
48
|
+
status: 502,
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
it('reports a network failure as status 0 without an errorBody', async () => {
|
|
52
|
+
vi.stubGlobal('fetch', vi.fn(async () => {
|
|
53
|
+
throw new Error('offline');
|
|
54
|
+
}));
|
|
55
|
+
await expect(cmsApi('/anything')).resolves.toEqual({ error: 'offline', status: 0 });
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
//# sourceMappingURL=api.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.test.js","sourceRoot":"","sources":["../../../src/__tests__/lib/api.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seo-service-autopilot.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/lib/seo-service-autopilot.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
/**
|
|
3
|
+
* Wire-level tests for the SEO Autopilot service wrappers. The render tests
|
|
4
|
+
* replace this module wholesale (`vi.mock('../../lib/seo-service.js')`), so
|
|
5
|
+
* URL construction, envelope unwrapping, and the 409 → `conflictFields`
|
|
6
|
+
* mapping are pinned here against a mocked `cmsApi`.
|
|
7
|
+
*/
|
|
8
|
+
const cmsApi = vi.fn();
|
|
9
|
+
vi.mock('../../lib/api.js', () => ({ cmsApi: (...args) => cmsApi(...args) }));
|
|
10
|
+
const svc = await import('../../lib/seo-service.js');
|
|
11
|
+
const SETTINGS = {
|
|
12
|
+
enabled: true,
|
|
13
|
+
enabledById: 'u1',
|
|
14
|
+
pausedAt: null,
|
|
15
|
+
pausedReason: null,
|
|
16
|
+
types: { 'missing-meta-title': true },
|
|
17
|
+
pausedTypes: {},
|
|
18
|
+
minBrandAlignment: 85,
|
|
19
|
+
redirectMinConfidence: 85,
|
|
20
|
+
maxPerRun: 5,
|
|
21
|
+
maxPerDay: 20,
|
|
22
|
+
verifyFailuresPerRun: 2,
|
|
23
|
+
outcomeWatch: { enabled: true, days: 14, dropRatio: 0.4, minPriorClicks: 50 },
|
|
24
|
+
lastRunAt: null,
|
|
25
|
+
lastRun: null,
|
|
26
|
+
governance: { issueFixApprovalRequired: false, redirectApprovalRequired: false },
|
|
27
|
+
};
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
// Block body on purpose: `mockReset()` returns the mock, and vitest would
|
|
30
|
+
// run a returned function as after-test cleanup.
|
|
31
|
+
cmsApi.mockReset();
|
|
32
|
+
});
|
|
33
|
+
describe('autopilot settings wrappers', () => {
|
|
34
|
+
it('fetchAutopilotSettings GETs /seo/autopilot/settings and returns the body', async () => {
|
|
35
|
+
cmsApi.mockResolvedValueOnce({ status: 200, data: SETTINGS });
|
|
36
|
+
await expect(svc.fetchAutopilotSettings()).resolves.toEqual({ settings: SETTINGS });
|
|
37
|
+
expect(cmsApi).toHaveBeenLastCalledWith('/seo/autopilot/settings');
|
|
38
|
+
});
|
|
39
|
+
it('fetchAutopilotSettings surfaces a transport error and rejects a malformed body', async () => {
|
|
40
|
+
cmsApi.mockResolvedValueOnce({ status: 500, error: 'boom' });
|
|
41
|
+
await expect(svc.fetchAutopilotSettings()).resolves.toEqual({ settings: null, error: 'boom' });
|
|
42
|
+
cmsApi.mockResolvedValueOnce({ status: 200, data: { enabled: 'yes' } });
|
|
43
|
+
await expect(svc.fetchAutopilotSettings()).resolves.toEqual({
|
|
44
|
+
settings: null,
|
|
45
|
+
error: 'Unexpected autopilot settings response',
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
it('updateAutopilotSettings PUTs the sparse patch verbatim and adopts the echoed policy', async () => {
|
|
49
|
+
cmsApi.mockResolvedValueOnce({ status: 200, data: { ...SETTINGS, maxPerRun: 9 } });
|
|
50
|
+
await expect(svc.updateAutopilotSettings({ maxPerRun: 9, outcomeWatch: { days: 7 } })).resolves.toEqual({ ok: true, settings: { ...SETTINGS, maxPerRun: 9 } });
|
|
51
|
+
expect(cmsApi).toHaveBeenLastCalledWith('/seo/autopilot/settings', {
|
|
52
|
+
method: 'PUT',
|
|
53
|
+
body: JSON.stringify({ maxPerRun: 9, outcomeWatch: { days: 7 } }),
|
|
54
|
+
});
|
|
55
|
+
cmsApi.mockResolvedValueOnce({ status: 400, error: 'maxPerRun must be an integer' });
|
|
56
|
+
await expect(svc.updateAutopilotSettings({ maxPerRun: 99 })).resolves.toEqual({
|
|
57
|
+
ok: false,
|
|
58
|
+
error: 'maxPerRun must be an integer',
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
it('runAutopilotNow POSTs an empty object and returns the run summary', async () => {
|
|
62
|
+
const summary = {
|
|
63
|
+
startedAt: '2026-09-07T04:00:00Z',
|
|
64
|
+
durationMs: 10,
|
|
65
|
+
applied: 1,
|
|
66
|
+
verifyFailed: 0,
|
|
67
|
+
reverted: 0,
|
|
68
|
+
gated: {},
|
|
69
|
+
applyOutcomes: {},
|
|
70
|
+
generated: { generated: 1, skipped: 0, failed: 0, haltedReason: null },
|
|
71
|
+
halted: false,
|
|
72
|
+
haltedReason: null,
|
|
73
|
+
};
|
|
74
|
+
cmsApi.mockResolvedValueOnce({ status: 200, data: summary });
|
|
75
|
+
await expect(svc.runAutopilotNow()).resolves.toEqual({ ok: true, summary });
|
|
76
|
+
expect(cmsApi).toHaveBeenLastCalledWith('/seo/autopilot/run', { method: 'POST', body: '{}' });
|
|
77
|
+
cmsApi.mockResolvedValueOnce({ status: 403, error: 'Admin only' });
|
|
78
|
+
await expect(svc.runAutopilotNow()).resolves.toEqual({ ok: false, error: 'Admin only' });
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
describe('fetchAutopilotApplied', () => {
|
|
82
|
+
const list = { docs: [], total: 0, page: 2, pageSize: 20, canRevert: true };
|
|
83
|
+
it('encodes page, pageSize, and the optional filters in that order', async () => {
|
|
84
|
+
cmsApi.mockResolvedValueOnce({ status: 200, data: list });
|
|
85
|
+
await expect(svc.fetchAutopilotApplied({ page: 2, pageSize: 20, status: 'applied' })).resolves.toEqual(list);
|
|
86
|
+
expect(cmsApi).toHaveBeenLastCalledWith('/seo/autopilot/applied?page=2&pageSize=20&status=applied');
|
|
87
|
+
cmsApi.mockResolvedValueOnce({ status: 200, data: list });
|
|
88
|
+
await svc.fetchAutopilotApplied({ page: 1, pageSize: 20, outcome: 'regressed' });
|
|
89
|
+
expect(cmsApi).toHaveBeenLastCalledWith('/seo/autopilot/applied?page=1&pageSize=20&outcome=regressed');
|
|
90
|
+
});
|
|
91
|
+
it('always sends page and pageSize even when no filter is set', async () => {
|
|
92
|
+
cmsApi.mockResolvedValueOnce({ status: 200, data: list });
|
|
93
|
+
await svc.fetchAutopilotApplied({ page: 1, pageSize: 20 });
|
|
94
|
+
expect(cmsApi).toHaveBeenLastCalledWith('/seo/autopilot/applied?page=1&pageSize=20');
|
|
95
|
+
});
|
|
96
|
+
it('throws on a transport error and falls back to an empty page on a missing body', async () => {
|
|
97
|
+
cmsApi.mockResolvedValueOnce({ status: 501, error: 'Run prisma migrate deploy' });
|
|
98
|
+
await expect(svc.fetchAutopilotApplied({ page: 1, pageSize: 20 })).rejects.toThrow('Run prisma migrate deploy');
|
|
99
|
+
cmsApi.mockResolvedValueOnce({ status: 200 });
|
|
100
|
+
await expect(svc.fetchAutopilotApplied({ page: 3, pageSize: 10 })).resolves.toEqual({
|
|
101
|
+
docs: [],
|
|
102
|
+
total: 0,
|
|
103
|
+
page: 3,
|
|
104
|
+
pageSize: 10,
|
|
105
|
+
canRevert: false,
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
describe('revertAutopilotChange', () => {
|
|
110
|
+
it('POSTs { force } to the encoded revert path and resolves ok', async () => {
|
|
111
|
+
cmsApi.mockResolvedValueOnce({ status: 200, data: { reverted: true } });
|
|
112
|
+
await expect(svc.revertAutopilotChange('la/1')).resolves.toEqual({ ok: true });
|
|
113
|
+
expect(cmsApi).toHaveBeenLastCalledWith('/seo/autopilot/applied/la%2F1/revert', {
|
|
114
|
+
method: 'POST',
|
|
115
|
+
body: JSON.stringify({ force: false }),
|
|
116
|
+
});
|
|
117
|
+
cmsApi.mockResolvedValueOnce({ status: 200, data: { reverted: true } });
|
|
118
|
+
await svc.revertAutopilotChange('la-1', true);
|
|
119
|
+
expect(cmsApi).toHaveBeenLastCalledWith('/seo/autopilot/applied/la-1/revert', {
|
|
120
|
+
method: 'POST',
|
|
121
|
+
body: JSON.stringify({ force: true }),
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
it('maps a 409 conflict body to conflictFields', async () => {
|
|
125
|
+
const error = 'metaTitle was edited since autopilot changed it';
|
|
126
|
+
cmsApi.mockResolvedValueOnce({
|
|
127
|
+
ok: false,
|
|
128
|
+
error,
|
|
129
|
+
code: 'conflict',
|
|
130
|
+
status: 409,
|
|
131
|
+
errorBody: { error, code: 'conflict', fields: ['metaTitle'] },
|
|
132
|
+
});
|
|
133
|
+
await expect(svc.revertAutopilotChange('la-1')).resolves.toEqual({
|
|
134
|
+
ok: false,
|
|
135
|
+
error,
|
|
136
|
+
conflictFields: ['metaTitle'],
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
it('does not report conflictFields when the error is not a conflict', async () => {
|
|
140
|
+
cmsApi.mockResolvedValueOnce({
|
|
141
|
+
ok: false,
|
|
142
|
+
error: 'Not found',
|
|
143
|
+
code: undefined,
|
|
144
|
+
status: 404,
|
|
145
|
+
errorBody: { error: 'Not found', fields: ['metaTitle'] },
|
|
146
|
+
});
|
|
147
|
+
const res = await svc.revertAutopilotChange('la-1');
|
|
148
|
+
expect(res).toEqual({ ok: false, error: 'Not found' });
|
|
149
|
+
expect(res).not.toHaveProperty('conflictFields');
|
|
150
|
+
});
|
|
151
|
+
it('filters non-string entries out of a conflict field list and tolerates a missing list', async () => {
|
|
152
|
+
cmsApi.mockResolvedValueOnce({
|
|
153
|
+
error: 'conflict',
|
|
154
|
+
code: 'conflict',
|
|
155
|
+
status: 409,
|
|
156
|
+
errorBody: { fields: ['metaTitle', 42, null, { name: 'x' }, 'metaDescription'] },
|
|
157
|
+
});
|
|
158
|
+
await expect(svc.revertAutopilotChange('la-1')).resolves.toEqual({
|
|
159
|
+
ok: false,
|
|
160
|
+
error: 'conflict',
|
|
161
|
+
conflictFields: ['metaTitle', 'metaDescription'],
|
|
162
|
+
});
|
|
163
|
+
cmsApi.mockResolvedValueOnce({ error: 'conflict', code: 'conflict', status: 409 });
|
|
164
|
+
await expect(svc.revertAutopilotChange('la-1')).resolves.toEqual({
|
|
165
|
+
ok: false,
|
|
166
|
+
error: 'conflict',
|
|
167
|
+
conflictFields: [],
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
//# sourceMappingURL=seo-service-autopilot.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seo-service-autopilot.test.js","sourceRoot":"","sources":["../../../src/__tests__/lib/seo-service-autopilot.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seo-service-proposals.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/lib/seo-service-proposals.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
const cmsApi = vi.fn();
|
|
3
|
+
vi.mock('../../lib/api.js', () => ({ cmsApi: (...args) => cmsApi(...args) }));
|
|
4
|
+
const svc = await import('../../lib/seo-service.js');
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
// Block body on purpose: `mockReset()` returns the mock, and vitest would
|
|
7
|
+
// run a returned function as after-test cleanup.
|
|
8
|
+
cmsApi.mockReset();
|
|
9
|
+
});
|
|
10
|
+
describe('proposal service helpers', () => {
|
|
11
|
+
it('fetchSeoProposals GETs /seo/proposals and throws on error', async () => {
|
|
12
|
+
cmsApi.mockResolvedValueOnce({ status: 500, error: 'boom' });
|
|
13
|
+
await expect(svc.fetchSeoProposals()).rejects.toThrow('boom');
|
|
14
|
+
cmsApi.mockResolvedValueOnce({
|
|
15
|
+
status: 200,
|
|
16
|
+
data: {
|
|
17
|
+
proposals: [],
|
|
18
|
+
counts: { issueFixes: 0, redirects: 0, stale: 0, eligibleForGeneration: 0 },
|
|
19
|
+
governance: { issueFixBulk: false, redirectBulk: false },
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
await expect(svc.fetchSeoProposals()).resolves.toMatchObject({ proposals: [] });
|
|
23
|
+
expect(cmsApi).toHaveBeenLastCalledWith('/seo/proposals');
|
|
24
|
+
});
|
|
25
|
+
it('fetchSeoProposals fills in autopilot when an older core omits it', async () => {
|
|
26
|
+
cmsApi.mockResolvedValueOnce({
|
|
27
|
+
status: 200,
|
|
28
|
+
data: {
|
|
29
|
+
proposals: [],
|
|
30
|
+
counts: { issueFixes: 0, redirects: 0, stale: 0, eligibleForGeneration: 0 },
|
|
31
|
+
governance: { issueFixBulk: true, redirectBulk: false },
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
await expect(svc.fetchSeoProposals()).resolves.toEqual({
|
|
35
|
+
proposals: [],
|
|
36
|
+
counts: { issueFixes: 0, redirects: 0, stale: 0, eligibleForGeneration: 0 },
|
|
37
|
+
governance: { issueFixBulk: true, redirectBulk: false },
|
|
38
|
+
autopilot: { enabled: false, pausedReason: null, lastRunAt: null, appliedLast7d: 0 },
|
|
39
|
+
});
|
|
40
|
+
// A server that does send it wins over the fallback.
|
|
41
|
+
const autopilot = { enabled: true, pausedReason: null, lastRunAt: null, appliedLast7d: 3 };
|
|
42
|
+
cmsApi.mockResolvedValueOnce({
|
|
43
|
+
status: 200,
|
|
44
|
+
data: {
|
|
45
|
+
proposals: [],
|
|
46
|
+
counts: { issueFixes: 0, redirects: 0, stale: 0, eligibleForGeneration: 0 },
|
|
47
|
+
governance: { issueFixBulk: true, redirectBulk: false },
|
|
48
|
+
autopilot,
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
await expect(svc.fetchSeoProposals()).resolves.toMatchObject({ autopilot });
|
|
52
|
+
});
|
|
53
|
+
it('generateSeoProposals POSTs confirm: true and returns the result or error', async () => {
|
|
54
|
+
cmsApi.mockResolvedValueOnce({
|
|
55
|
+
status: 200,
|
|
56
|
+
data: { generated: 3, skipped: 1, failed: 0, remaining: 2, haltedReason: null },
|
|
57
|
+
});
|
|
58
|
+
await expect(svc.generateSeoProposals()).resolves.toEqual({
|
|
59
|
+
result: { generated: 3, skipped: 1, failed: 0, remaining: 2, haltedReason: null },
|
|
60
|
+
});
|
|
61
|
+
expect(cmsApi).toHaveBeenCalledWith('/seo/proposals/generate', {
|
|
62
|
+
method: 'POST',
|
|
63
|
+
body: JSON.stringify({ confirm: true }),
|
|
64
|
+
});
|
|
65
|
+
cmsApi.mockResolvedValueOnce({ status: 429, error: 'AI rate limit reached.' });
|
|
66
|
+
await expect(svc.generateSeoProposals()).resolves.toEqual({ error: 'AI rate limit reached.' });
|
|
67
|
+
});
|
|
68
|
+
it('bulkApplySeoProposals flags governance_blocked distinctly', async () => {
|
|
69
|
+
cmsApi.mockResolvedValueOnce({
|
|
70
|
+
status: 403,
|
|
71
|
+
error: 'Enable "Allow bulk apply"',
|
|
72
|
+
code: 'governance_blocked',
|
|
73
|
+
});
|
|
74
|
+
await expect(svc.bulkApplySeoProposals([{ kind: 'issue-fix', id: 'i1', fingerprint: 'f' }])).resolves.toEqual({ error: 'Enable "Allow bulk apply"', governanceBlocked: true });
|
|
75
|
+
cmsApi.mockResolvedValueOnce({
|
|
76
|
+
status: 200,
|
|
77
|
+
data: {
|
|
78
|
+
results: [{ kind: 'issue-fix', id: 'i1', status: 'applied' }],
|
|
79
|
+
applied: 1,
|
|
80
|
+
failed: 0,
|
|
81
|
+
pending: 0,
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
await expect(svc.bulkApplySeoProposals([{ kind: 'issue-fix', id: 'i1' }])).resolves.toEqual({
|
|
85
|
+
result: {
|
|
86
|
+
results: [{ kind: 'issue-fix', id: 'i1', status: 'applied' }],
|
|
87
|
+
applied: 1,
|
|
88
|
+
failed: 0,
|
|
89
|
+
pending: 0,
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
it('dismissSeoIssueFix POSTs to the encoded issue path', async () => {
|
|
94
|
+
cmsApi.mockResolvedValueOnce({ status: 200, data: { dismissed: true } });
|
|
95
|
+
await expect(svc.dismissSeoIssueFix('a/b')).resolves.toEqual({});
|
|
96
|
+
expect(cmsApi).toHaveBeenCalledWith('/seo/issues/a%2Fb/dismiss-fix', { method: 'POST' });
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
//# sourceMappingURL=seo-service-proposals.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seo-service-proposals.test.js","sourceRoot":"","sources":["../../../src/__tests__/lib/seo-service-proposals.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,6 +15,7 @@ describe('seoTabForPath', () => {
|
|
|
15
15
|
expect(seoTabForPath('/seo/links')).toBe('technical');
|
|
16
16
|
expect(seoTabForPath('/seo/redirects')).toBe('redirects');
|
|
17
17
|
expect(seoTabForPath('/seo/audit')).toBe('audit');
|
|
18
|
+
expect(seoTabForPath('/seo/proposals')).toBe('proposals');
|
|
18
19
|
});
|
|
19
20
|
it('returns null for non-SEO paths so they fall through', () => {
|
|
20
21
|
expect(seoTabForPath('/dashboard')).toBeNull();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"seo-tab-for-path.test.js","sourceRoot":"","sources":["../../../src/__tests__/router/seo-tab-for-path.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAE7C,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAElE,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,uEAAuE;QACvE,yEAAyE;QACzE,MAAM,CAAC,aAAa,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACvD,MAAM,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;IACzD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QAC9C,MAAM,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QACrD,MAAM,CAAC,aAAa,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QACxD,MAAM,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;QACzD,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;QACrD,MAAM,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;QACzD,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"seo-tab-for-path.test.js","sourceRoot":"","sources":["../../../src/__tests__/router/seo-tab-for-path.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAE7C,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAElE,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,uEAAuE;QACvE,yEAAyE;QACzE,MAAM,CAAC,aAAa,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACvD,MAAM,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;IACzD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QAC9C,MAAM,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QACrD,MAAM,CAAC,aAAa,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QACxD,MAAM,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;QACzD,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;QACrD,MAAM,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;QACzD,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACjD,MAAM,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;IAC3D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;QAC9C,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;QAC1C,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;QAC3C,MAAM,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;IAC/C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qEAAqE,EAAE,GAAG,EAAE;QAC7E,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE,CAAC;YAClC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAA;QAC5C,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,2EAA2E;QAC3E,wEAAwE;QACxE,KAAK,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,kBAAkB,CAAC,EAAE,CAAC;YAChE,MAAM,CAAC,cAAc,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;YACtC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAA;QAC5C,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -34,6 +34,7 @@ const createRedirectRule = vi.fn(async (_p) => ({}));
|
|
|
34
34
|
const updateRedirectRule = vi.fn(async (_id, _p) => ({}));
|
|
35
35
|
const deleteRedirectRule = vi.fn(async (_id) => ({}));
|
|
36
36
|
const generate404RecoverySuggestions = vi.fn(async () => ({}));
|
|
37
|
+
const saveRedirectRecoverySettings = vi.fn(async (_p) => ({}));
|
|
37
38
|
vi.mock('../../lib/seo-service.js', () => ({
|
|
38
39
|
fetchRedirectOverview: vi.fn(async () => ({
|
|
39
40
|
activeRedirects: 2,
|
|
@@ -57,9 +58,9 @@ vi.mock('../../lib/seo-service.js', () => ({
|
|
|
57
58
|
fetchRedirectRecoverySettings: vi.fn(async () => ({
|
|
58
59
|
aiRerank: false,
|
|
59
60
|
autoApply: false,
|
|
60
|
-
autoApplyMinConfidence:
|
|
61
|
+
autoApplyMinConfidence: 85,
|
|
61
62
|
})),
|
|
62
|
-
saveRedirectRecoverySettings:
|
|
63
|
+
saveRedirectRecoverySettings: (p) => saveRedirectRecoverySettings(p),
|
|
63
64
|
}));
|
|
64
65
|
vi.mock('sonner', () => ({
|
|
65
66
|
toast: { success: vi.fn(), error: vi.fn(), info: vi.fn(), loading: vi.fn() },
|
|
@@ -70,6 +71,8 @@ beforeEach(() => {
|
|
|
70
71
|
createRedirectRule.mockClear();
|
|
71
72
|
updateRedirectRule.mockClear();
|
|
72
73
|
deleteRedirectRule.mockClear();
|
|
74
|
+
generate404RecoverySuggestions.mockClear();
|
|
75
|
+
saveRedirectRecoverySettings.mockClear();
|
|
73
76
|
});
|
|
74
77
|
describe('Redirects inline editor pane', () => {
|
|
75
78
|
it('opens the pane on row click with the rule loaded', async () => {
|
|
@@ -129,19 +132,34 @@ describe('Redirects inline editor pane', () => {
|
|
|
129
132
|
expect(createRedirectRule).not.toHaveBeenCalled();
|
|
130
133
|
});
|
|
131
134
|
});
|
|
132
|
-
describe('
|
|
133
|
-
it('
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
135
|
+
describe('404 recovery settings', () => {
|
|
136
|
+
it('points auto-apply at SEO Autopilot instead of exposing its own controls', async () => {
|
|
137
|
+
const onNavigate = vi.fn();
|
|
138
|
+
render(_jsx(RedirectsTab, { onNavigate: onNavigate }));
|
|
139
|
+
await screen.findByRole('button', { name: '/old-path' });
|
|
140
|
+
// Task 8 moved the auto-apply policy into the autopilot; the card keeps
|
|
141
|
+
// AI re-ranking only and links to the Autopilot settings card.
|
|
142
|
+
expect(screen.getByLabelText('AI re-ranking')).toBeTruthy();
|
|
143
|
+
expect(screen.queryByLabelText(/Auto-apply high-confidence redirects/)).toBeNull();
|
|
144
|
+
expect(screen.queryByLabelText(/Auto-apply minimum confidence/)).toBeNull();
|
|
145
|
+
fireEvent.click(screen.getByRole('button', { name: 'SEO Autopilot' }));
|
|
146
|
+
expect(onNavigate).toHaveBeenCalledWith('/settings?tab=seo');
|
|
147
|
+
expect(screen.queryByRole('link')).toBeNull();
|
|
148
|
+
});
|
|
149
|
+
it('saves only the AI re-ranking flag', async () => {
|
|
150
|
+
render(_jsx(RedirectsTab, {}));
|
|
151
|
+
await screen.findByRole('button', { name: '/old-path' });
|
|
152
|
+
fireEvent.click(screen.getByLabelText('AI re-ranking'));
|
|
153
|
+
fireEvent.click(screen.getByRole('button', { name: 'Save settings' }));
|
|
154
|
+
await waitFor(() => expect(saveRedirectRecoverySettings).toHaveBeenCalledWith({ aiRerank: true }));
|
|
155
|
+
});
|
|
156
|
+
it('reports generation success without the retired auto-apply / governance messages', async () => {
|
|
157
|
+
generate404RecoverySuggestions.mockResolvedValueOnce({});
|
|
138
158
|
const { toast } = await import('sonner');
|
|
139
159
|
render(_jsx(RedirectsTab, {}));
|
|
140
160
|
fireEvent.click(await screen.findByRole('button', { name: /Generate suggestions/ }));
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
await waitFor(() => expect(toast.info).toHaveBeenCalledWith(expect.stringContaining('requires human approval')));
|
|
144
|
-
expect(toast.success).toHaveBeenCalledWith('Generated 404 recovery suggestions.');
|
|
161
|
+
await waitFor(() => expect(toast.success).toHaveBeenCalledWith('Generated 404 recovery suggestions.'));
|
|
162
|
+
expect(toast.info).not.toHaveBeenCalled();
|
|
145
163
|
});
|
|
146
164
|
});
|
|
147
165
|
//# sourceMappingURL=redirects-pane.render.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redirects-pane.render.test.js","sourceRoot":"","sources":["../../../src/__tests__/views/redirects-pane.render.test.tsx"],"names":[],"mappings":";AAAA,gCAAgC;AAChC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAA;AAE3E;;;;;GAKG;AAEH,SAAS,QAAQ,CAAC,OAAgC,EAAE;IAClD,OAAO;QACL,EAAE,EAAE,IAAI;QACR,IAAI,EAAE,GAAY;QAClB,QAAQ,EAAE,WAAW;QACrB,MAAM,EAAE,WAAW;QACnB,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,CAAC;QACX,aAAa,EAAE,KAAK;QACpB,IAAI,EAAE,CAAC;QACP,SAAS,EAAE,IAAI;QACf,QAAQ,EAAE,IAAI;QACd,KAAK,EAAE,KAAK;QACZ,MAAM,EAAE,QAAQ;QAChB,KAAK,EAAE,IAAI;QACX,SAAS,EAAE,sBAAsB;QACjC,SAAS,EAAE,sBAAsB;QACjC,GAAG,IAAI;KACR,CAAA;AACH,CAAC;AAED,MAAM,KAAK,GAAG,CAAC,QAAQ,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC,CAAA;AAE5F,MAAM,kBAAkB,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,KAAK,CAAC,CAAA;AACnD,MAAM,kBAAkB,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,EAAW,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;AAC7D,MAAM,kBAAkB,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,GAAW,EAAE,EAAW,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;AAC1E,MAAM,kBAAkB,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,GAAW,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;AAC7D,MAAM,8BAA8B,GAAG,EAAE,CAAC,EAAE,
|
|
1
|
+
{"version":3,"file":"redirects-pane.render.test.js","sourceRoot":"","sources":["../../../src/__tests__/views/redirects-pane.render.test.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seo-autopilot-applied.render.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/views/seo-autopilot-applied.render.test.tsx"],"names":[],"mappings":""}
|