|
|
@@ -0,0 +1,146 @@
|
|
|
+import { mount, createLocalVue } from "@vue/test-utils"
|
|
|
+import ElementUI from "element-ui"
|
|
|
+import ArticleEdit from "@/views/admin/ArticleEdit.vue"
|
|
|
+import {
|
|
|
+ adminArticleCreate,
|
|
|
+ adminArticleUpdate,
|
|
|
+ adminArticlePublish,
|
|
|
+ adminArticleCategoriesList
|
|
|
+} from "@/api/article.js"
|
|
|
+
|
|
|
+jest.mock("@/router", () => ({
|
|
|
+ __esModule: true,
|
|
|
+ default: { push: jest.fn(), replace: jest.fn(), back: jest.fn() }
|
|
|
+}))
|
|
|
+jest.mock("@/api/article.js", () => ({
|
|
|
+ adminArticleCreate: jest.fn(),
|
|
|
+ adminArticleUpdate: jest.fn(),
|
|
|
+ adminArticlePublish: jest.fn(),
|
|
|
+ adminArticleCategoriesList: jest.fn().mockResolvedValue({ data: [] }),
|
|
|
+ adminArticleDetail: jest.fn(),
|
|
|
+ adminArticleSubmitReview: jest.fn(),
|
|
|
+ adminArticleReDraft: jest.fn()
|
|
|
+}))
|
|
|
+jest.mock("@/api/dimension-weight.js", () => ({
|
|
|
+ saveDimensionWeights: jest.fn().mockResolvedValue({}),
|
|
|
+ getDimensionWeights: jest.fn().mockResolvedValue({ data: null })
|
|
|
+}))
|
|
|
+jest.mock("@/utils/editorAssetUpload", () => ({
|
|
|
+ getUploadHeaders: jest.fn(() => ({})),
|
|
|
+ getEditorCustomAlert: jest.fn(() => ({})),
|
|
|
+ buildEditorAssetMenuConf: jest.fn(() => ({})),
|
|
|
+ ASSET_MENU_KEY: "assetLibrary",
|
|
|
+ registerAssetLibraryMenu: jest.fn(),
|
|
|
+ setAssetMenuHandler: jest.fn(),
|
|
|
+ buildAssetToolbarConfig: jest.fn(() => ({}))
|
|
|
+}))
|
|
|
+jest.mock("@wangeditor/editor-for-vue", () => ({
|
|
|
+ Editor: { render: h => h("div") },
|
|
|
+ Toolbar: { render: h => h("div") }
|
|
|
+}))
|
|
|
+jest.mock("@wangeditor/editor", () => ({
|
|
|
+ DomEditor: {},
|
|
|
+ SlateTransforms: {},
|
|
|
+ SlatePath: {}
|
|
|
+}))
|
|
|
+jest.mock("@wangeditor/editor/dist/css/style.css", () => ({}), { virtual: true })
|
|
|
+
|
|
|
+const localVue = createLocalVue()
|
|
|
+localVue.use(ElementUI)
|
|
|
+
|
|
|
+function mountArticleEdit() {
|
|
|
+ const $message = { success: jest.fn(), error: jest.fn(), warning: jest.fn() }
|
|
|
+ const $alert = jest.fn(() => Promise.resolve())
|
|
|
+ const $confirm = jest.fn(() => Promise.resolve("confirm"))
|
|
|
+ const $router = { push: jest.fn() }
|
|
|
+ const wrapper = mount(ArticleEdit, {
|
|
|
+ localVue,
|
|
|
+ mocks: { $route: { query: {} }, $router, $alert, $message, $confirm },
|
|
|
+ stubs: {
|
|
|
+ PageHeader: true,
|
|
|
+ Editor: true,
|
|
|
+ Toolbar: true,
|
|
|
+ AssetPicker: true,
|
|
|
+ DimensionWeightPicker: true,
|
|
|
+ ContentDimensionThresholdEditor: true
|
|
|
+ }
|
|
|
+ })
|
|
|
+ return { wrapper, $message, $alert, $confirm, $router }
|
|
|
+}
|
|
|
+
|
|
|
+beforeEach(() => {
|
|
|
+ jest.clearAllMocks()
|
|
|
+})
|
|
|
+
|
|
|
+describe("ArticleEdit 知识库校验状态处理", () => {
|
|
|
+ it("保存返回 REJECTED → 弹警告(含失败句 + 已自动转为草稿)", async () => {
|
|
|
+ const { wrapper, $alert, $message } = mountArticleEdit()
|
|
|
+ adminArticleCreate.mockResolvedValue({
|
|
|
+ code: 200,
|
|
|
+ data: {
|
|
|
+ id: 1,
|
|
|
+ kbCheckStatus: "REJECTED",
|
|
|
+ kbCheckResult: JSON.stringify({ failed: [{ text: "此句未在知识库中找到出处" }] })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ wrapper.vm.form.title = "益生菌选购指南"
|
|
|
+ wrapper.vm.form.content = "双歧杆菌有助于维持肠道菌群平衡。此句未在知识库中找到出处。"
|
|
|
+ await wrapper.vm.$nextTick()
|
|
|
+
|
|
|
+ await wrapper.vm.handleSave(false)
|
|
|
+
|
|
|
+ expect(adminArticleCreate).toHaveBeenCalled()
|
|
|
+ expect($alert).toHaveBeenCalled()
|
|
|
+ const alertArgs = $alert.mock.calls[0][0]
|
|
|
+ expect(alertArgs).toContain("已自动转为草稿")
|
|
|
+ expect(alertArgs).toContain("此句未在知识库中找到出处")
|
|
|
+ expect($message.success).not.toHaveBeenCalled()
|
|
|
+ })
|
|
|
+
|
|
|
+ it("发布 REJECTED → 触发 $confirm 二次确认后才调发布接口", async () => {
|
|
|
+ const { wrapper, $confirm } = mountArticleEdit()
|
|
|
+ // 模拟已加载的 REJECTED 文章
|
|
|
+ wrapper.vm.isEdit = true
|
|
|
+ wrapper.vm.form.id = 1
|
|
|
+ wrapper.vm.kbCheckStatus = "REJECTED"
|
|
|
+ adminArticleUpdate.mockResolvedValue({ code: 200, data: { kbCheckStatus: "REJECTED" } })
|
|
|
+ adminArticlePublish.mockResolvedValue({ code: 200, data: { kbCheckRejected: true } })
|
|
|
+
|
|
|
+ await wrapper.vm.handleSave(true)
|
|
|
+
|
|
|
+ expect($confirm).toHaveBeenCalled()
|
|
|
+ expect($confirm.mock.calls[0][0]).toContain("强制发布")
|
|
|
+ expect(adminArticlePublish).toHaveBeenCalled()
|
|
|
+ })
|
|
|
+
|
|
|
+ it("发布 REJECTED 但用户取消 $confirm → 不调发布接口", async () => {
|
|
|
+ const { wrapper, $confirm } = mountArticleEdit()
|
|
|
+ wrapper.vm.isEdit = true
|
|
|
+ wrapper.vm.form.id = 1
|
|
|
+ wrapper.vm.kbCheckStatus = "REJECTED"
|
|
|
+ $confirm.mockRejectedValue(new Error("cancel"))
|
|
|
+ adminArticleUpdate.mockResolvedValue({ code: 200, data: { kbCheckStatus: "REJECTED" } })
|
|
|
+
|
|
|
+ await wrapper.vm.handleSave(true)
|
|
|
+
|
|
|
+ expect($confirm).toHaveBeenCalled()
|
|
|
+ expect(adminArticleUpdate).not.toHaveBeenCalled()
|
|
|
+ expect(adminArticlePublish).not.toHaveBeenCalled()
|
|
|
+ })
|
|
|
+
|
|
|
+ it("保存返回 APPROVED → 绿色成功提示,无警告", async () => {
|
|
|
+ const { wrapper, $alert, $message } = mountArticleEdit()
|
|
|
+ adminArticleCreate.mockResolvedValue({
|
|
|
+ code: 200,
|
|
|
+ data: { id: 1, kbCheckStatus: "APPROVED", kbCheckResult: JSON.stringify({ all_passed: true }) }
|
|
|
+ })
|
|
|
+ wrapper.vm.form.title = "益生菌选购指南"
|
|
|
+ wrapper.vm.form.content = "双歧杆菌有助于维持肠道菌群平衡,菌株 LGG 有研究支持。"
|
|
|
+ await wrapper.vm.$nextTick()
|
|
|
+
|
|
|
+ await wrapper.vm.handleSave(false)
|
|
|
+
|
|
|
+ expect($alert).not.toHaveBeenCalled()
|
|
|
+ expect($message.success).toHaveBeenCalled()
|
|
|
+ })
|
|
|
+})
|