* feat: add backlinks setup and overview workflow * save * fix backlinks timeseries and refine overview layout * update backlinks table guidance * refactor backlinks CI cleanup * refactor backlinks page state colocation * fix backlinks access error handling Differentiate DataForSEO subscription access failures from billing issues and preserve exact page hosts for page-level backlink lookups. * fix backlinks project scoping and error states * simplify backlinks billing and lazy loading * harden backlinks profiling and access flow * refine backlinks access status typing * update backlinks scope selection and access handling * fix backlinks scope fallback and cache scoping * fix backlinks ci checks * docs: simplify backlinks pricing * refine backlinks search: move scope toggle below input, remove redundant description * refine backlinks summaries and help text * refine backlinks table sorting * fix backlinks invalid target handling * delete docs * fix backlinks scope inference and domain normalization * docs: mark backlinks as a supported workflow * fix backlinks links badge wrapping * test: split backlinks test suites
48 lines
1.4 KiB
TypeScript
48 lines
1.4 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
import type { AppError } from "@/server/lib/errors";
|
|
import { assertBacklinksProjectAccess } from "@/server/features/backlinks/backlinksProjectAccess";
|
|
import { KeywordResearchRepository } from "@/server/features/keywords/repositories/KeywordResearchRepository";
|
|
|
|
vi.mock(
|
|
"@/server/features/keywords/repositories/KeywordResearchRepository",
|
|
() => ({
|
|
KeywordResearchRepository: {
|
|
getProject: vi.fn(),
|
|
},
|
|
}),
|
|
);
|
|
|
|
describe("assertBacklinksProjectAccess", () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it("returns the project when the user has access", async () => {
|
|
const project = {
|
|
id: "project-1",
|
|
userId: "user-1",
|
|
name: "Project 1",
|
|
domain: null,
|
|
pagespeedApiKey: null,
|
|
createdAt: "2026-03-14T00:00:00.000Z",
|
|
};
|
|
vi.mocked(KeywordResearchRepository.getProject).mockResolvedValue(project);
|
|
|
|
await expect(
|
|
assertBacklinksProjectAccess("user-1", "project-1"),
|
|
).resolves.toBe(project);
|
|
});
|
|
|
|
it("throws when the user does not have project access", async () => {
|
|
vi.mocked(KeywordResearchRepository.getProject).mockResolvedValue(
|
|
undefined,
|
|
);
|
|
|
|
await expect(
|
|
assertBacklinksProjectAccess("user-1", "project-1"),
|
|
).rejects.toMatchObject({
|
|
code: "NOT_FOUND",
|
|
} satisfies Partial<AppError>);
|
|
});
|
|
});
|