Compare commits
94 Commits
main
...
feature/st
Author | SHA1 | Date | |
---|---|---|---|
|
ac0216cb64 | ||
|
bcb41c68fb | ||
|
ef2126f1ca | ||
|
1125e2ae39 | ||
|
054095e499 | ||
|
81df0eae05 | ||
|
0a27554bb6 | ||
|
5dfd3d941f | ||
|
60f96386a9 | ||
|
7f832ce885 | ||
|
47ea148866 | ||
|
129a803e9a | ||
|
bc0597efe0 | ||
|
365bea25e1 | ||
|
3d5f04b4a8 | ||
|
f3ebc11b3f | ||
|
d5669352ed | ||
|
0b686ab4ac | ||
|
54a86e1501 | ||
|
cdb8b6532a | ||
|
56c37fce3c | ||
|
43b20b1be6 | ||
|
b749cfa6f6 | ||
|
0b4e1fa13b | ||
|
43001a12c7 | ||
|
d3c2180ac8 | ||
|
63e16e1694 | ||
|
c6cc0d22e5 | ||
|
949a989dcf | ||
|
9427e0efe5 | ||
|
70c236c879 | ||
|
3d31245ae5 | ||
|
98fc21995a | ||
|
f6e3778a2d | ||
|
6775a9df5e | ||
|
3cb843e493 | ||
|
bc3ce31c9e | ||
|
3e7f0cac90 | ||
|
f3b8ab278a | ||
|
013f9ac811 | ||
|
9e07e8330a | ||
|
8950073141 | ||
|
4d580bb789 | ||
|
f73bfb0ab3 | ||
|
8109d350e4 | ||
|
b233023bb3 | ||
|
fd7cc2ea96 | ||
|
724535a735 | ||
|
b5c7ec3008 | ||
|
c5698ad631 | ||
|
6fb337633c | ||
|
42b8d74ead | ||
|
d8e76dc2e6 | ||
|
4f2cd4ca47 | ||
|
82c98ec1f5 | ||
|
fbc654f21b | ||
|
9d89a1ceca | ||
|
517906f77f | ||
|
681e8fa3ae | ||
|
4d5c3eb15d | ||
|
9a35de7e36 | ||
|
c4b730c8af | ||
|
8ea8869ca7 | ||
|
7e5a8ae5c1 | ||
|
cf495b60d1 | ||
|
fb57eaaba7 | ||
|
b494bd6174 | ||
|
310fe0d325 | ||
|
ba418c5cd7 | ||
|
9596cd07a1 | ||
|
2ed5b64b18 | ||
|
492e0055f0 | ||
|
93938702fe | ||
|
e8907ca4fb | ||
|
2b32850046 | ||
|
da1749fb53 | ||
|
5bc5eb8719 | ||
|
3227a799f9 | ||
|
8740685a4d | ||
|
5c3915a74d | ||
|
b1958ec8ff | ||
|
bc39e9933d | ||
|
36dd5a4f2d | ||
|
a101878313 | ||
|
32e43b8260 | ||
|
9afb23c08e | ||
|
eaa1abda82 | ||
|
6431cc3210 | ||
|
122f584cad | ||
|
f45cf7982f | ||
|
2f0736fd95 | ||
|
6c72344204 | ||
|
61fd6e09af | ||
|
349b4dad8c |
@ -1,5 +1,5 @@
|
||||
# 镜像集成
|
||||
FROM node:18-slim
|
||||
FROM node:18
|
||||
|
||||
# 设置工作区间
|
||||
WORKDIR /xiaoju-survey
|
||||
|
2
LICENSE
2
LICENSE
@ -186,7 +186,7 @@
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright (C) 2023 Beijing Didi Infinity Technology and Development Co.,Ltd. All rights reserved.
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
25
README.md
25
README.md
@ -35,27 +35,23 @@
|
||||
|
||||
# 功能特性
|
||||
|
||||
**🌈 易用**
|
||||
**🌈 好用**
|
||||
|
||||
- 多类型数据采集,轻松创建调研表单:文本输入、数据选择、评分、投票、文件上传等。
|
||||
- 多类型数据采集,轻松创建调研表单。
|
||||
|
||||
- 智能逻辑编排,设计多规则动态表单:显示逻辑、跳转逻辑、选项引用、题目引用等。
|
||||
- 智能逻辑编排,设计多规则动态表单。
|
||||
|
||||
- 精细权限管理,支持高效团队协同:空间管理、多角色权限管理等。
|
||||
|
||||
- 数据在线分析和导出,洞察调研结果:数据导出、回收数据管理、分题统计、交叉分析等。
|
||||
- 数据在线分析和导出,洞察调研结果。
|
||||
|
||||
**🎨 好看**
|
||||
|
||||
- 主题自由定制,适配您的品牌:自定义颜色、背景、图片、Logo、结果页规则等。
|
||||
- 主题自由定制,适配您的品牌。
|
||||
|
||||
- 无缝嵌入各终端,满足不同场景需求:多端嵌入式小问卷 SDK。
|
||||
- 无缝嵌入各终端,满足不同场景需求。
|
||||
|
||||
**🚀 安全、可扩展**
|
||||
**🚀 好扩展**
|
||||
|
||||
- 安全能力可扩展,提供安全相关建设的经验指导:传输加密、敏感词库、发布审查等。
|
||||
|
||||
- 自定义 Hook 配置,轻松集成多方系统与各类工具:数据推送集成、消息推送集成等。
|
||||
- 自定义 Hook 配置,轻松集成多方系统与各类工具。
|
||||
|
||||
<img src="https://github.com/didi/xiaoju-survey/assets/16012672/dd427471-368d-49d9-bc44-13c34d84e3be" width="700" />
|
||||
|
||||
@ -144,7 +140,7 @@ _(在线平台建设中)_
|
||||
|
||||
_(手册编写中)_
|
||||
|
||||
<br />
|
||||
<br /><br />
|
||||
|
||||
## Star
|
||||
|
||||
@ -157,7 +153,6 @@ _(手册编写中)_
|
||||
官方群会发布项目最新消息、建设计划和社区活动,欢迎你的加入。
|
||||
|
||||
<img src="https://img-hxy021.didistatic.com/static/starimg/img/KXKvc7sjHz1700061188156.png" width="200" />
|
||||
|
||||
_任何问题和合作可以联系小助手。_
|
||||
|
||||
## 案例
|
||||
@ -174,4 +169,4 @@ _任何问题和合作可以联系小助手。_
|
||||
|
||||
## CHANGELOG
|
||||
|
||||
关注项目重大变更:[MAJOR CHANGELOG](https://github.com/didi/xiaoju-survey/issues/48)。
|
||||
关注重大项目变更:[MAJOR CHANGELOG](https://github.com/didi/xiaoju-survey/issues/48)。
|
50
README_EN.md
50
README_EN.md
@ -33,43 +33,27 @@
|
||||
|
||||
  The internal system has accumulated over 40 question types and more than 100 selected templates, suitable for market research, customer satisfaction surveys, online exams, voting, reporting, evaluations, and many other scenarios. In terms of data capabilities, it has been honed through hundreds of millions of iterations, resulting in the ability to provide online reports with per-question statistics, cross-analysis, and multi-channel analysis, quickly meeting professional analysis needs.
|
||||
|
||||
# Features
|
||||
# Function Overview
|
||||
|
||||
**🌈 Easy to use**
|
||||
- Questionnaire Management: Create, edit, distribute, collect, data analysis.
|
||||
|
||||
- Multi-type data collection, easy to create forms: text input, data selection, scoring, voting, file upload, etc.
|
||||
- Diverse Question Types: Single-line input, multi-line input, single choice, multiple choice, true/false, rating, voting, etc.
|
||||
|
||||
- Smart logic arrangement, design multi-rule dynamic forms: display logic, jump logic, option reference, title reference, etc.
|
||||
- User Management: Login, registration, permissions management.
|
||||
|
||||
- Multiple permission management, support efficient team collaboration: space management, multi-role permission management, etc.
|
||||
- Data Security: Encrypted transmission, data masking, etc.
|
||||
|
||||
- Online data analysis and export, insight into survey results: data export, recycled data management, sub-topic statistics, cross-analysis, etc.
|
||||
|
||||
**🎨 Good-looking**
|
||||
|
||||
- Free customization of themes to adapt to your brand: custom colors, backgrounds, pictures, logos, result page rules, etc.
|
||||
|
||||
- Seamlessly embedded in various terminals to meet the needs of different scenarios: multi-terminal embedded small questionnaire SDK.
|
||||
|
||||
**🚀 Secure and scalable**
|
||||
|
||||
- Scalable security capabilities, providing experience guidance for security-related construction: encrypted transmission, data masking, etc.
|
||||
|
||||
- Customized Hook configuration, easy integration of multiple systems and various tools: data push, message push, etc.
|
||||
> For more comprehensive features, please refer to the [documentation](https://xiaojusurvey.didi.cn/docs/next/document/%E4%BA%A7%E5%93%81%E6%89%8B%E5%86%8C/%E5%8A%9F%E8%83%BD%E4%BB%8B%E7%BB%8D/%E5%9F%BA%E7%A1%80%E6%B5%81%E7%A8%8B).
|
||||
|
||||
<img src="https://github.com/didi/xiaoju-survey/assets/16012672/508ce30f-0ae8-4f5f-84a7-e96de8238a7f" width="700" />
|
||||
|
||||
1. For more comprehensive features, please refer to the [documentation](https://xiaojusurvey.didi.cn/docs/next/document/%E4%BA%A7%E5%93%81%E6%89%8B%E5%86%8C/%E5%8A%9F%E8%83%BD%E4%BB%8B%E7%BB%8D/%E5%9F%BA%E7%A1%80%E6%B5%81%E7%A8%8B).
|
||||
|
||||
2. Both individual and enterprise users can quickly build survey solutions specific to their fields.
|
||||
_**(Both individual and enterprise users can quickly build survey solutions specific to their fields.)**_
|
||||
|
||||
# Technology
|
||||
|
||||
Web: Vue3 + ElementPlus; Multi-end rendering for C-end (planning).
|
||||
|
||||
Server: NestJS + MongoDB; Java ([under construction](https://github.com/didi/xiaoju-survey/issues/306)).
|
||||
|
||||
Online Platform: (under construction).
|
||||
Server: Nestjs + MongoDB; Java ([under construction](https://github.com/didi/xiaoju-survey/issues/306)).
|
||||
|
||||
Intelligent Foundation: (planning).
|
||||
|
||||
@ -161,7 +145,7 @@ npm run local
|
||||
|
||||
#### 1.Configure Database
|
||||
|
||||
> The project uses MongoDB: [MongoDB Guide](https://xiaojusurvey.didi.cn/docs/next/document/%E6%A6%82%E8%BF%B0/%E6%95%B0%E6%8D%AE%E5%BA%93#%E5%AE%89%E8%A3%85)
|
||||
> The project uses MongoDB: [MongoDB Guide](https://xiaojusurvey.didi.cn/docs/next/document/%E6%A6%82%E8%BF%B0/%E6%95%B0%E6%8D%AE%E5%BA%93)
|
||||
|
||||
Configure the database, check MongoDB configuration.
|
||||
|
||||
@ -207,18 +191,22 @@ Create and publish a questionnaire.
|
||||
|
||||
<br /><br />
|
||||
|
||||
## Star
|
||||
|
||||
Open source is not easy. If this project helps you, please star it ❤️❤️❤️. Your support is our greatest motivation.
|
||||
|
||||
[![Star History Chart](https://api.star-history.com/svg?repos=didi/xiaoju-survey&type=Date)](https://star-history.com/#didi/xiaoju-survey&Date)
|
||||
|
||||
## WeChat Group
|
||||
|
||||
The official group will release the latest project news, construction plans, and community activities. Any questions and cooperation can contact the assistant:
|
||||
|
||||
<img src="https://img-hxy021.didistatic.com/static/starimg/img/KXKvc7sjHz1700061188156.png" width="200" />
|
||||
|
||||
## QQ Group
|
||||
|
||||
The official group will release the latest project news, construction plans, and community activities. Welcome to join:
|
||||
|
||||
[<img src="https://img-hxy021.didistatic.com/static/starimg/img/iJUmLIHKV21700192846057.png" width="210" />](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=P61UJI_q8AzizyBLGOm-bUvzNrUnSQq-&authKey=yZFtL9biGB5yiIME3%2Bi%2Bf6XMOdTNiuf0pCIaviEEAIryySNzVy6LJ4xl7uHdEcrM&noverify=0&group_code=920623419)
|
||||
|
||||
## Star
|
||||
|
||||
Open source is not easy. If this project helps you, please star it ❤️❤️❤️. Your support is our greatest motivation.
|
||||
|
||||
## Feedback
|
||||
|
||||
If you use this project, please leave feedback:[I'm using](https://github.com/didi/xiaoju-survey/issues/64), Your support is our greatest.
|
||||
|
@ -15,7 +15,7 @@ services:
|
||||
- xiaoju-survey
|
||||
|
||||
xiaoju-survey:
|
||||
image: "xiaojusurvey/xiaoju-survey:1.3.0-slim" # 最新版本:https://hub.docker.com/r/xiaojusurvey/xiaoju-survey/tags
|
||||
image: "xiaojusurvey/xiaoju-survey:1.2.0-slim" # 最新版本:https://hub.docker.com/r/xiaojusurvey/xiaoju-survey/tags
|
||||
container_name: xiaoju-survey
|
||||
restart: always
|
||||
ports:
|
||||
|
@ -1,17 +0,0 @@
|
||||
XIAOJU_SURVEY_MONGO_DB_NAME=xiaojuSurvey
|
||||
XIAOJU_SURVEY_MONGO_URL=
|
||||
XIAOJU_SURVEY_MONGO_AUTH_SOURCE=admin
|
||||
|
||||
XIAOJU_SURVEY_REDIS_HOST=
|
||||
XIAOJU_SURVEY_REDIS_PORT=
|
||||
XIAOJU_SURVEY_REDIS_USERNAME=
|
||||
XIAOJU_SURVEY_REDIS_PASSWORD=
|
||||
XIAOJU_SURVEY_REDIS_DB=
|
||||
|
||||
XIAOJU_SURVEY_RESPONSE_AES_ENCRYPT_SECRET_KEY=dataAesEncryptSecretKey
|
||||
XIAOJU_SURVEY_HTTP_DATA_ENCRYPT_TYPE=rsa
|
||||
|
||||
XIAOJU_SURVEY_JWT_SECRET=xiaojuSurveyJwtSecret
|
||||
XIAOJU_SURVEY_JWT_EXPIRES_IN=8h
|
||||
|
||||
XIAOJU_SURVEY_LOGGER_FILENAME=./logs/app.log
|
@ -95,9 +95,7 @@
|
||||
"^.+\\.(t|j)s$": "ts-jest"
|
||||
},
|
||||
"collectCoverageFrom": [
|
||||
"**/*.(t|j)s",
|
||||
"!**/*.module.ts",
|
||||
"!**/upgrade.*.ts"
|
||||
"**/*.(t|j)s"
|
||||
],
|
||||
"coverageDirectory": "../coverage",
|
||||
"testEnvironment": "node",
|
||||
|
@ -88,10 +88,17 @@ export interface MsgContent {
|
||||
msg_9004: string;
|
||||
}
|
||||
|
||||
export interface JumpConfig {
|
||||
type: string;
|
||||
link: string;
|
||||
buttonText?: string;
|
||||
}
|
||||
|
||||
export interface SubmitConf {
|
||||
submitTitle: string;
|
||||
confirmAgain: ConfirmAgain;
|
||||
msgContent: MsgContent;
|
||||
jumpConfig?: JumpConfig;
|
||||
}
|
||||
|
||||
// 白名单类型
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { AppModule } from './app.module';
|
||||
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
|
||||
import './report';
|
||||
import 'scripts/run-report';
|
||||
|
||||
async function bootstrap() {
|
||||
const PORT = process.env.PORT || 3000;
|
||||
|
30
server/src/models/__test/base.entity.spec.ts
Normal file
30
server/src/models/__test/base.entity.spec.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { BaseEntity } from '../base.entity';
|
||||
import { RECORD_STATUS } from 'src/enums';
|
||||
|
||||
describe('BaseEntity', () => {
|
||||
let baseEntity: BaseEntity;
|
||||
|
||||
beforeEach(() => {
|
||||
baseEntity = new BaseEntity();
|
||||
});
|
||||
|
||||
it('should initialize default info before insert', () => {
|
||||
const now = Date.now();
|
||||
baseEntity.initDefaultInfo();
|
||||
|
||||
expect(baseEntity.curStatus.status).toBe(RECORD_STATUS.NEW);
|
||||
expect(baseEntity.curStatus.date).toBeCloseTo(now, -3);
|
||||
expect(baseEntity.statusList).toHaveLength(1);
|
||||
expect(baseEntity.statusList[0].status).toBe(RECORD_STATUS.NEW);
|
||||
expect(baseEntity.statusList[0].date).toBeCloseTo(now, -3);
|
||||
expect(baseEntity.createDate).toBeCloseTo(now, -3);
|
||||
expect(baseEntity.updateDate).toBeCloseTo(now, -3);
|
||||
});
|
||||
|
||||
it('should update updateDate before update', () => {
|
||||
const now = Date.now();
|
||||
baseEntity.onUpdate();
|
||||
|
||||
expect(baseEntity.updateDate).toBeCloseTo(now, -3);
|
||||
});
|
||||
});
|
@ -1,57 +0,0 @@
|
||||
import { SurveyMeta } from '../surveyMeta.entity';
|
||||
import { RECORD_STATUS, RECORD_SUB_STATUS } from 'src/enums';
|
||||
|
||||
// 模拟日期
|
||||
const mockDateNow = Date.now();
|
||||
|
||||
describe('SurveyMeta Entity', () => {
|
||||
let surveyMeta: SurveyMeta;
|
||||
|
||||
// 在每个测试之前,初始化 SurveyMeta 实例
|
||||
beforeEach(() => {
|
||||
surveyMeta = new SurveyMeta();
|
||||
// 模拟 Date.now() 返回固定的时间
|
||||
jest.spyOn(Date, 'now').mockReturnValue(mockDateNow);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks(); // 每次测试后还原所有 mock
|
||||
});
|
||||
|
||||
it('should set default curStatus and subStatus on insert when they are not provided', () => {
|
||||
surveyMeta.initDefaultInfo();
|
||||
|
||||
// 验证 curStatus 是否被初始化为默认值
|
||||
expect(surveyMeta.curStatus).toEqual({
|
||||
status: RECORD_STATUS.NEW,
|
||||
date: mockDateNow,
|
||||
});
|
||||
|
||||
// 验证 statusList 是否包含 curStatus
|
||||
expect(surveyMeta.statusList).toEqual([
|
||||
{
|
||||
status: RECORD_STATUS.NEW,
|
||||
date: mockDateNow,
|
||||
},
|
||||
]);
|
||||
|
||||
// 验证 subStatus 是否被初始化为默认值
|
||||
expect(surveyMeta.subStatus).toEqual({
|
||||
status: RECORD_SUB_STATUS.DEFAULT,
|
||||
date: mockDateNow,
|
||||
});
|
||||
});
|
||||
|
||||
it('should initialize statusList if curStatus is provided but statusList is empty', () => {
|
||||
surveyMeta.curStatus = null;
|
||||
|
||||
surveyMeta.initDefaultInfo();
|
||||
|
||||
expect(surveyMeta.statusList).toEqual([
|
||||
{
|
||||
status: RECORD_STATUS.NEW,
|
||||
date: expect.any(Number),
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
@ -206,8 +206,8 @@ describe('UserService', () => {
|
||||
it('should return a list of users by username', async () => {
|
||||
const username = 'test';
|
||||
const userList = [
|
||||
{ _id: new ObjectId(), username: 'testUser1', createdAt: new Date() },
|
||||
{ _id: new ObjectId(), username: 'testUser2', createdAt: new Date() },
|
||||
{ _id: new ObjectId(), username: 'testUser1', createDate: new Date() },
|
||||
{ _id: new ObjectId(), username: 'testUser2', createDate: new Date() },
|
||||
];
|
||||
|
||||
jest
|
||||
@ -226,7 +226,7 @@ describe('UserService', () => {
|
||||
},
|
||||
skip: 0,
|
||||
take: 10,
|
||||
select: ['_id', 'username', 'createdAt'],
|
||||
select: ['_id', 'username', 'createDate'],
|
||||
});
|
||||
expect(result).toEqual(userList);
|
||||
});
|
||||
@ -237,12 +237,12 @@ describe('UserService', () => {
|
||||
{
|
||||
_id: new ObjectId(idList[0]),
|
||||
username: 'testUser1',
|
||||
createdAt: new Date(),
|
||||
createDate: new Date(),
|
||||
},
|
||||
{
|
||||
_id: new ObjectId(idList[1]),
|
||||
username: 'testUser2',
|
||||
createdAt: new Date(),
|
||||
createDate: new Date(),
|
||||
},
|
||||
];
|
||||
|
||||
@ -258,7 +258,7 @@ describe('UserService', () => {
|
||||
$in: idList.map((id) => new ObjectId(id)),
|
||||
},
|
||||
},
|
||||
select: ['_id', 'username', 'createdAt'],
|
||||
select: ['_id', 'username', 'createDate'],
|
||||
});
|
||||
expect(result).toEqual(userList);
|
||||
});
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
MESSAGE_PUSHING_TYPE,
|
||||
MESSAGE_PUSHING_HOOK,
|
||||
} from 'src/enums/messagePushing';
|
||||
import { RECORD_STATUS } from 'src/enums';
|
||||
|
||||
describe('MessagePushingTaskDto', () => {
|
||||
let dto: MessagePushingTaskDto;
|
||||
@ -33,9 +34,9 @@ describe('MessagePushingTaskDto', () => {
|
||||
});
|
||||
|
||||
it('should have a type', () => {
|
||||
dto.type = MESSAGE_PUSHING_TYPE.HTTP;
|
||||
dto.type = MESSAGE_PUSHING_TYPE.HTTP; // Set your desired type here
|
||||
expect(dto.type).toBeDefined();
|
||||
expect(dto.type).toEqual(MESSAGE_PUSHING_TYPE.HTTP);
|
||||
expect(dto.type).toEqual(MESSAGE_PUSHING_TYPE.HTTP); // Adjust based on your enum
|
||||
});
|
||||
|
||||
it('should have a push address', () => {
|
||||
@ -45,13 +46,13 @@ describe('MessagePushingTaskDto', () => {
|
||||
});
|
||||
|
||||
it('should have a trigger hook', () => {
|
||||
dto.triggerHook = MESSAGE_PUSHING_HOOK.RESPONSE_INSERTED;
|
||||
dto.triggerHook = MESSAGE_PUSHING_HOOK.RESPONSE_INSERTED; // Set your desired hook here
|
||||
expect(dto.triggerHook).toBeDefined();
|
||||
expect(dto.triggerHook).toEqual(MESSAGE_PUSHING_HOOK.RESPONSE_INSERTED);
|
||||
expect(dto.triggerHook).toEqual(MESSAGE_PUSHING_HOOK.RESPONSE_INSERTED); // Adjust based on your enum
|
||||
});
|
||||
|
||||
it('should have an array of surveys', () => {
|
||||
dto.surveys = ['survey1', 'survey2'];
|
||||
dto.surveys = ['survey1', 'survey2']; // Set your desired surveys here
|
||||
expect(dto.surveys).toBeDefined();
|
||||
expect(dto.surveys).toEqual(['survey1', 'survey2']);
|
||||
});
|
||||
@ -61,6 +62,13 @@ describe('MessagePushingTaskDto', () => {
|
||||
expect(dto.owner).toBeDefined();
|
||||
expect(dto.owner).toBe('test_owner');
|
||||
});
|
||||
|
||||
it('should have current status', () => {
|
||||
dto.curStatus = { status: RECORD_STATUS.NEW, date: Date.now() };
|
||||
expect(dto.curStatus).toBeDefined();
|
||||
expect(dto.curStatus.status).toEqual(RECORD_STATUS.NEW);
|
||||
expect(dto.curStatus.date).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('CodeDto', () => {
|
||||
|
@ -117,9 +117,6 @@ describe('MessagePushingTaskService', () => {
|
||||
expect(result).toEqual(tasks);
|
||||
expect(repository.find).toHaveBeenCalledWith({
|
||||
where: {
|
||||
isDeleted: {
|
||||
$ne: true,
|
||||
},
|
||||
ownerId: mockOwnerId,
|
||||
surveys: { $all: [surveyId] },
|
||||
triggerHook: hook,
|
||||
@ -147,19 +144,9 @@ describe('MessagePushingTaskService', () => {
|
||||
where: {
|
||||
ownerId: mockOwnerId,
|
||||
_id: new ObjectId(taskId),
|
||||
isDeleted: {
|
||||
$ne: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
it('should throw an error when message pushing task is not found', async () => {
|
||||
const taskId = '65afc62904d5db18534c0f78';
|
||||
jest.spyOn(repository, 'findOne').mockResolvedValue(null); // 模拟未找到任务
|
||||
const mockOwnerId = '66028642292c50f8b71a9eee';
|
||||
|
||||
await expect(service.findOne({ id: taskId, ownerId: mockOwnerId }));
|
||||
});
|
||||
});
|
||||
|
||||
describe('update', () => {
|
||||
@ -196,20 +183,6 @@ describe('MessagePushingTaskService', () => {
|
||||
});
|
||||
expect(repository.save).toHaveBeenCalledWith(updatedTask);
|
||||
});
|
||||
it('should throw an error if the task to be updated is not found', async () => {
|
||||
const taskId = '65afc62904d5db18534c0f78';
|
||||
const updateDto: UpdateMessagePushingTaskDto = { name: 'Updated Task' };
|
||||
jest.spyOn(repository, 'findOne').mockResolvedValue(null); // 模拟任务未找到
|
||||
const mockOwnerId = '66028642292c50f8b71a9eee';
|
||||
|
||||
await expect(
|
||||
service.update({
|
||||
ownerId: mockOwnerId,
|
||||
id: taskId,
|
||||
updateData: updateDto,
|
||||
}),
|
||||
).rejects.toThrow(`Message pushing task with id ${taskId} not found`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('remove', () => {
|
||||
@ -231,40 +204,16 @@ describe('MessagePushingTaskService', () => {
|
||||
expect(result).toEqual(updateResult);
|
||||
expect(repository.updateOne).toHaveBeenCalledWith(
|
||||
{
|
||||
ownerId: mockOperatorId,
|
||||
_id: new ObjectId(taskId),
|
||||
},
|
||||
{
|
||||
$set: {
|
||||
isDeleted: true,
|
||||
operatorId: mockOperatorId,
|
||||
operator: mockOperator,
|
||||
deletedAt: expect.any(Date),
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
it('should throw an error if the task to be removed is not found', async () => {
|
||||
const taskId = '65afc62904d5db18534c0f78';
|
||||
jest
|
||||
.spyOn(repository, 'updateOne')
|
||||
.mockResolvedValue({ modifiedCount: 0 }); // 模拟删除失败
|
||||
const mockOperatorId = '66028642292c50f8b71a9eee';
|
||||
const mockOperator = 'mockOperator';
|
||||
|
||||
const result = await service.remove({
|
||||
id: taskId,
|
||||
operatorId: mockOperatorId,
|
||||
operator: mockOperator,
|
||||
});
|
||||
|
||||
expect(result.modifiedCount).toBe(0);
|
||||
expect(repository.updateOne).toHaveBeenCalledWith(
|
||||
{
|
||||
_id: new ObjectId(taskId),
|
||||
},
|
||||
expect.any(Object),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('surveyAuthorizeTask', () => {
|
||||
@ -294,35 +243,8 @@ describe('MessagePushingTaskService', () => {
|
||||
$push: {
|
||||
surveys: surveyId,
|
||||
},
|
||||
$set: {
|
||||
updatedAt: expect.any(Date),
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
it('should not add the surveyId if it already exists in the task', async () => {
|
||||
const taskId = '65afc62904d5db18534c0f78';
|
||||
const surveyId = '65af380475b64545e5277dd9';
|
||||
const mockOwnerId = '66028642292c50f8b71a9eee';
|
||||
|
||||
jest
|
||||
.spyOn(repository, 'updateOne')
|
||||
.mockResolvedValue({ modifiedCount: 0 }); // 模拟重复添加
|
||||
const result = await service.surveyAuthorizeTask({
|
||||
taskId,
|
||||
surveyId,
|
||||
ownerId: mockOwnerId,
|
||||
});
|
||||
|
||||
expect(result.modifiedCount).toBe(0);
|
||||
expect(repository.updateOne).toHaveBeenCalledWith(
|
||||
{
|
||||
_id: new ObjectId(taskId),
|
||||
surveys: { $nin: [surveyId] }, // 确保只有不包含时才插入
|
||||
ownerId: mockOwnerId,
|
||||
},
|
||||
expect.any(Object),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -37,4 +37,9 @@ describe('UpdateMessagePushingTaskDto', () => {
|
||||
dto.surveys = null;
|
||||
expect(dto.surveys).toBeNull();
|
||||
});
|
||||
|
||||
it('should have a nullable curStatus', () => {
|
||||
dto.curStatus = null;
|
||||
expect(dto.curStatus).toBeNull();
|
||||
});
|
||||
});
|
||||
|
@ -63,14 +63,14 @@ export class MessagePushingTaskService {
|
||||
});
|
||||
}
|
||||
|
||||
findOne({
|
||||
async findOne({
|
||||
id,
|
||||
ownerId,
|
||||
}: {
|
||||
id: string;
|
||||
ownerId: string;
|
||||
}): Promise<MessagePushingTask> {
|
||||
return this.messagePushingTaskRepository.findOne({
|
||||
return await this.messagePushingTaskRepository.findOne({
|
||||
where: {
|
||||
ownerId,
|
||||
_id: new ObjectId(id),
|
||||
|
@ -75,25 +75,6 @@ describe('CollaboratorService', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteCollaborator', () => {
|
||||
it('should delete a collaborator by userId and surveyId', async () => {
|
||||
const deleteOneSpy = jest
|
||||
.spyOn(repository, 'deleteOne')
|
||||
.mockResolvedValue({ acknowledged: true, deletedCount: 1 });
|
||||
|
||||
const result = await service.deleteCollaborator({
|
||||
userId: '1',
|
||||
surveyId: '1',
|
||||
});
|
||||
|
||||
expect(deleteOneSpy).toHaveBeenCalledWith({
|
||||
userId: '1',
|
||||
surveyId: '1',
|
||||
});
|
||||
expect(result).toEqual({ acknowledged: true, deletedCount: 1 });
|
||||
});
|
||||
});
|
||||
|
||||
describe('batchCreate', () => {
|
||||
it('should batch create collaborators', async () => {
|
||||
const insertManySpy = jest
|
||||
@ -105,193 +86,15 @@ describe('CollaboratorService', () => {
|
||||
const result = await service.batchCreate({
|
||||
surveyId: '1',
|
||||
collaboratorList: [{ userId: '1', permissions: [] }],
|
||||
creator: 'testCreator',
|
||||
creatorId: 'testCreatorId',
|
||||
});
|
||||
|
||||
expect(insertManySpy).toHaveBeenCalledWith([
|
||||
{
|
||||
userId: '1',
|
||||
permissions: [],
|
||||
surveyId: '1',
|
||||
createdAt: expect.any(Date),
|
||||
updatedAt: expect.any(Date),
|
||||
creator: 'testCreator',
|
||||
creatorId: 'testCreatorId',
|
||||
},
|
||||
{ surveyId: '1', userId: '1', permissions: [] },
|
||||
]);
|
||||
expect(result).toEqual({ insertedCount: 1 });
|
||||
});
|
||||
});
|
||||
|
||||
describe('changeUserPermission', () => {
|
||||
it("should update a user's permissions", async () => {
|
||||
const updateOneSpy = jest
|
||||
.spyOn(repository, 'updateOne')
|
||||
.mockResolvedValue({});
|
||||
|
||||
const result = await service.changeUserPermission({
|
||||
userId: '1',
|
||||
surveyId: '1',
|
||||
permission: 'read',
|
||||
operator: 'testOperator',
|
||||
operatorId: 'testOperatorId',
|
||||
});
|
||||
|
||||
expect(updateOneSpy).toHaveBeenCalledWith(
|
||||
{
|
||||
surveyId: '1',
|
||||
userId: '1',
|
||||
},
|
||||
{
|
||||
$set: {
|
||||
permission: 'read',
|
||||
operator: 'testOperator',
|
||||
operatorId: 'testOperatorId',
|
||||
updatedAt: expect.any(Date),
|
||||
},
|
||||
},
|
||||
);
|
||||
expect(result).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('batchDelete', () => {
|
||||
it('should batch delete collaborators', async () => {
|
||||
const mockResult = { acknowledged: true, deletedCount: 1 };
|
||||
const deleteManySpy = jest
|
||||
.spyOn(repository, 'deleteMany')
|
||||
.mockResolvedValue(mockResult);
|
||||
|
||||
const collaboratorId = new ObjectId().toString();
|
||||
|
||||
const result = await service.batchDelete({
|
||||
surveyId: '1',
|
||||
idList: [collaboratorId],
|
||||
});
|
||||
|
||||
const expectedQuery = {
|
||||
surveyId: '1',
|
||||
$or: [
|
||||
{
|
||||
_id: {
|
||||
$in: [new ObjectId(collaboratorId)],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
expect(logger.info).toHaveBeenCalledWith(JSON.stringify(expectedQuery));
|
||||
expect(deleteManySpy).toHaveBeenCalledWith(expectedQuery);
|
||||
expect(result).toEqual(mockResult);
|
||||
});
|
||||
it('should batch delete collaborators by idList and userIdList', async () => {
|
||||
const collaboratorId = new ObjectId().toString();
|
||||
const deleteManySpy = jest
|
||||
.spyOn(repository, 'deleteMany')
|
||||
.mockResolvedValue({ acknowledged: true, deletedCount: 2 });
|
||||
|
||||
const result = await service.batchDelete({
|
||||
idList: [collaboratorId],
|
||||
userIdList: ['user1', 'user2'],
|
||||
surveyId: '1',
|
||||
});
|
||||
|
||||
const expectedQuery = {
|
||||
surveyId: '1',
|
||||
$or: [
|
||||
{
|
||||
userId: {
|
||||
$in: ['user1', 'user2'],
|
||||
},
|
||||
},
|
||||
{
|
||||
_id: {
|
||||
$in: [new ObjectId(collaboratorId)],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
expect(deleteManySpy).toHaveBeenCalledWith(expectedQuery);
|
||||
expect(result).toEqual({ acknowledged: true, deletedCount: 2 });
|
||||
});
|
||||
|
||||
it('should handle batch delete with neIdList only', async () => {
|
||||
const neCollaboratorId = new ObjectId().toString();
|
||||
const deleteManySpy = jest
|
||||
.spyOn(repository, 'deleteMany')
|
||||
.mockResolvedValue({ acknowledged: true, deletedCount: 1 });
|
||||
|
||||
const result = await service.batchDelete({
|
||||
neIdList: [neCollaboratorId],
|
||||
surveyId: '1',
|
||||
});
|
||||
|
||||
const expectedQuery = {
|
||||
surveyId: '1',
|
||||
$or: [
|
||||
{
|
||||
_id: {
|
||||
$nin: [new ObjectId(neCollaboratorId)],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
expect(deleteManySpy).toHaveBeenCalledWith(expectedQuery);
|
||||
expect(result).toEqual({ acknowledged: true, deletedCount: 1 });
|
||||
});
|
||||
});
|
||||
|
||||
describe('batchDeleteBySurveyId', () => {
|
||||
it('should batch delete collaborators by survey id', async () => {
|
||||
const mockResult = { acknowledged: true, deletedCount: 1 };
|
||||
const deleteManySpy = jest
|
||||
.spyOn(repository, 'deleteMany')
|
||||
.mockResolvedValue(mockResult);
|
||||
|
||||
const surveyId = new ObjectId().toString();
|
||||
|
||||
const result = await service.batchDeleteBySurveyId(surveyId);
|
||||
|
||||
expect(deleteManySpy).toHaveBeenCalledWith({
|
||||
surveyId,
|
||||
});
|
||||
expect(result).toEqual(mockResult);
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateById', () => {
|
||||
it('should update collaborator by id', async () => {
|
||||
const updateOneSpy = jest
|
||||
.spyOn(repository, 'updateOne')
|
||||
.mockResolvedValue({});
|
||||
const collaboratorId = new ObjectId().toString();
|
||||
const result = await service.updateById({
|
||||
collaboratorId,
|
||||
permissions: [],
|
||||
operator: 'testOperator',
|
||||
operatorId: 'testOperatorId',
|
||||
});
|
||||
|
||||
expect(updateOneSpy).toHaveBeenCalledWith(
|
||||
{
|
||||
_id: new ObjectId(collaboratorId),
|
||||
},
|
||||
{
|
||||
$set: {
|
||||
permissions: [],
|
||||
operator: 'testOperator',
|
||||
operatorId: 'testOperatorId',
|
||||
updatedAt: expect.any(Date),
|
||||
},
|
||||
},
|
||||
);
|
||||
expect(result).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSurveyCollaboratorList', () => {
|
||||
it('should return a list of collaborators for a survey', async () => {
|
||||
const collaboratorId = new ObjectId().toString();
|
||||
@ -318,6 +121,38 @@ describe('CollaboratorService', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCollaboratorListByIds', () => {
|
||||
it('should return a list of collaborators by ids', async () => {
|
||||
const collaboratorId = new ObjectId().toString();
|
||||
const findSpy = jest.spyOn(repository, 'find').mockResolvedValue([
|
||||
{
|
||||
_id: new ObjectId(collaboratorId),
|
||||
surveyId: '1',
|
||||
userId: '1',
|
||||
permissions: [],
|
||||
},
|
||||
] as Collaborator[]);
|
||||
|
||||
const result = await service.getCollaboratorListByIds({
|
||||
idList: [collaboratorId],
|
||||
});
|
||||
|
||||
expect(findSpy).toHaveBeenCalledWith({
|
||||
_id: {
|
||||
$in: [new ObjectId(collaboratorId)],
|
||||
},
|
||||
});
|
||||
expect(result).toEqual([
|
||||
{
|
||||
_id: new ObjectId(collaboratorId),
|
||||
surveyId: '1',
|
||||
userId: '1',
|
||||
permissions: [],
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCollaborator', () => {
|
||||
it('should return a collaborator', async () => {
|
||||
const collaboratorId = new ObjectId().toString();
|
||||
@ -348,6 +183,127 @@ describe('CollaboratorService', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('changeUserPermission', () => {
|
||||
it("should update a user's permissions", async () => {
|
||||
const updateOneSpy = jest
|
||||
.spyOn(repository, 'updateOne')
|
||||
.mockResolvedValue({});
|
||||
|
||||
const result = await service.changeUserPermission({
|
||||
userId: '1',
|
||||
surveyId: '1',
|
||||
permission: 'read',
|
||||
});
|
||||
|
||||
expect(updateOneSpy).toHaveBeenCalledWith(
|
||||
{
|
||||
surveyId: '1',
|
||||
userId: '1',
|
||||
},
|
||||
{
|
||||
$set: {
|
||||
permission: 'read',
|
||||
},
|
||||
},
|
||||
);
|
||||
expect(result).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteCollaborator', () => {
|
||||
it('should delete a collaborator', async () => {
|
||||
const mockResult = { acknowledged: true, deletedCount: 1 };
|
||||
const deleteOneSpy = jest
|
||||
.spyOn(repository, 'deleteOne')
|
||||
.mockResolvedValue(mockResult);
|
||||
|
||||
const result = await service.deleteCollaborator({
|
||||
userId: '1',
|
||||
surveyId: '1',
|
||||
});
|
||||
|
||||
expect(deleteOneSpy).toHaveBeenCalledWith({
|
||||
userId: '1',
|
||||
surveyId: '1',
|
||||
});
|
||||
expect(result).toEqual(mockResult);
|
||||
});
|
||||
});
|
||||
|
||||
describe('batchDelete', () => {
|
||||
it('should batch delete collaborators', async () => {
|
||||
const mockResult = { acknowledged: true, deletedCount: 1 };
|
||||
const deleteManySpy = jest
|
||||
.spyOn(repository, 'deleteMany')
|
||||
.mockResolvedValue(mockResult);
|
||||
|
||||
const collaboratorId = new ObjectId().toString();
|
||||
|
||||
const result = await service.batchDelete({
|
||||
surveyId: '1',
|
||||
idList: [collaboratorId],
|
||||
});
|
||||
|
||||
const expectedQuery = {
|
||||
surveyId: '1',
|
||||
$or: [
|
||||
{
|
||||
_id: {
|
||||
$in: [new ObjectId(collaboratorId)],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
expect(logger.info).toHaveBeenCalledWith(JSON.stringify(expectedQuery));
|
||||
expect(deleteManySpy).toHaveBeenCalledWith(expectedQuery);
|
||||
expect(result).toEqual(mockResult);
|
||||
});
|
||||
});
|
||||
|
||||
describe('batchDeleteBySurveyId', () => {
|
||||
it('should batch delete collaborators by survey id', async () => {
|
||||
const mockResult = { acknowledged: true, deletedCount: 1 };
|
||||
const deleteManySpy = jest
|
||||
.spyOn(repository, 'deleteMany')
|
||||
.mockResolvedValue(mockResult);
|
||||
|
||||
const surveyId = new ObjectId().toString();
|
||||
|
||||
const result = await service.batchDeleteBySurveyId(surveyId);
|
||||
|
||||
expect(deleteManySpy).toHaveBeenCalledWith({
|
||||
surveyId,
|
||||
});
|
||||
expect(result).toEqual(mockResult);
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateById', () => {
|
||||
it('should update collaborator by id', async () => {
|
||||
const updateOneSpy = jest
|
||||
.spyOn(repository, 'updateOne')
|
||||
.mockResolvedValue({});
|
||||
const collaboratorId = new ObjectId().toString();
|
||||
const result = await service.updateById({
|
||||
collaboratorId,
|
||||
permissions: [],
|
||||
});
|
||||
|
||||
expect(updateOneSpy).toHaveBeenCalledWith(
|
||||
{
|
||||
_id: new ObjectId(collaboratorId),
|
||||
},
|
||||
{
|
||||
$set: {
|
||||
permissions: [],
|
||||
},
|
||||
},
|
||||
);
|
||||
expect(result).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCollaboratorListByUserId', () => {
|
||||
it('should return a list of collaborators by user id', async () => {
|
||||
const userId = new ObjectId().toString();
|
||||
@ -371,48 +327,5 @@ describe('CollaboratorService', () => {
|
||||
{ _id: '1', surveyId: '1', userId, permissions: [] },
|
||||
]);
|
||||
});
|
||||
|
||||
it('should return a list of collaborators by their IDs', async () => {
|
||||
const collaboratorId1 = new ObjectId().toString();
|
||||
const collaboratorId2 = new ObjectId().toString();
|
||||
const findSpy = jest.spyOn(repository, 'find').mockResolvedValue([
|
||||
{
|
||||
_id: new ObjectId(collaboratorId1),
|
||||
surveyId: '1',
|
||||
userId: 'user1',
|
||||
permissions: [],
|
||||
},
|
||||
{
|
||||
_id: new ObjectId(collaboratorId2),
|
||||
surveyId: '2',
|
||||
userId: 'user2',
|
||||
permissions: [],
|
||||
},
|
||||
] as Collaborator[]);
|
||||
|
||||
const result = await service.getCollaboratorListByIds({
|
||||
idList: [collaboratorId1, collaboratorId2],
|
||||
});
|
||||
|
||||
expect(findSpy).toHaveBeenCalledWith({
|
||||
_id: {
|
||||
$in: [new ObjectId(collaboratorId1), new ObjectId(collaboratorId2)],
|
||||
},
|
||||
});
|
||||
expect(result).toEqual([
|
||||
{
|
||||
_id: new ObjectId(collaboratorId1),
|
||||
surveyId: '1',
|
||||
userId: 'user1',
|
||||
permissions: [],
|
||||
},
|
||||
{
|
||||
_id: new ObjectId(collaboratorId2),
|
||||
surveyId: '2',
|
||||
userId: 'user2',
|
||||
permissions: [],
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -109,8 +109,8 @@ describe('DataStatisticController', () => {
|
||||
},
|
||||
],
|
||||
listBody: [
|
||||
{ diffTime: '0.5', createdAt: '2024-02-11' },
|
||||
{ diffTime: '0.5', createdAt: '2024-02-11' },
|
||||
{ diffTime: '0.5', createDate: '2024-02-11' },
|
||||
{ diffTime: '0.5', createDate: '2024-02-11' },
|
||||
],
|
||||
};
|
||||
|
||||
@ -155,8 +155,8 @@ describe('DataStatisticController', () => {
|
||||
},
|
||||
],
|
||||
listBody: [
|
||||
{ diffTime: '0.5', createdAt: '2024-02-11', data123: '15200000000' },
|
||||
{ diffTime: '0.5', createdAt: '2024-02-11', data123: '13800000000' },
|
||||
{ diffTime: '0.5', createDate: '2024-02-11', data123: '15200000000' },
|
||||
{ diffTime: '0.5', createDate: '2024-02-11', data123: '13800000000' },
|
||||
],
|
||||
};
|
||||
|
||||
@ -212,8 +212,8 @@ describe('DataStatisticController', () => {
|
||||
date: 1717158851823,
|
||||
},
|
||||
],
|
||||
createdAt: 1717158851823,
|
||||
updatedAt: 1717159136025,
|
||||
createDate: 1717158851823,
|
||||
updateDate: 1717159136025,
|
||||
title: '问卷调研',
|
||||
surveyPath: 'ZdGNzTTR',
|
||||
code: {
|
||||
@ -275,6 +275,11 @@ describe('DataStatisticController', () => {
|
||||
again_text: '确认要提交吗?',
|
||||
},
|
||||
link: '',
|
||||
jumpConfig: {
|
||||
type: 'link',
|
||||
link: '',
|
||||
buttonText: '',
|
||||
},
|
||||
},
|
||||
logicConf: {
|
||||
showLogicConf: [],
|
||||
|
@ -151,8 +151,8 @@ describe('DataStatisticService', () => {
|
||||
date: 1710340863123.0,
|
||||
},
|
||||
],
|
||||
createdAt: 1710340863123.0,
|
||||
updatedAt: 1710340863123.0,
|
||||
createDate: 1710340863123.0,
|
||||
updateDate: 1710340863123.0,
|
||||
},
|
||||
] as unknown as Array<SurveyResponse>;
|
||||
|
||||
@ -196,7 +196,7 @@ describe('DataStatisticService', () => {
|
||||
data413: expect.any(Number),
|
||||
data863: expect.any(String),
|
||||
diffTime: expect.any(String),
|
||||
createdAt: expect.any(String),
|
||||
createDate: expect.any(String),
|
||||
}),
|
||||
]),
|
||||
});
|
||||
@ -273,8 +273,8 @@ describe('DataStatisticService', () => {
|
||||
date: 1710400232161.0,
|
||||
},
|
||||
],
|
||||
createdAt: 1710400232161.0,
|
||||
updatedAt: 1710400232161.0,
|
||||
createDate: 1710400232161.0,
|
||||
updateDate: 1710400232161.0,
|
||||
},
|
||||
] as unknown as Array<SurveyResponse>;
|
||||
|
||||
@ -295,7 +295,7 @@ describe('DataStatisticService', () => {
|
||||
expect(result.listBody).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
createdAt: expect.any(String),
|
||||
createDate: expect.any(String),
|
||||
data405: expect.any(String),
|
||||
data450: expect.any(String),
|
||||
data458: expect.any(String),
|
||||
|
@ -145,7 +145,7 @@ describe('DownloadTaskController', () => {
|
||||
filename: 'mockFile.csv',
|
||||
url: 'http://mock-url.com',
|
||||
fileSize: 1024,
|
||||
createdAt: Date.now(),
|
||||
createDate: Date.now(),
|
||||
},
|
||||
],
|
||||
};
|
||||
@ -219,13 +219,10 @@ describe('DownloadTaskController', () => {
|
||||
describe('deleteFileByName', () => {
|
||||
it('should delete a download task successfully', async () => {
|
||||
const mockBody = { taskId: 'mockTaskId' };
|
||||
const mockUserId = new ObjectId();
|
||||
const mockReq = {
|
||||
user: { _id: mockUserId, username: 'mockUsername' },
|
||||
};
|
||||
const mockReq = { user: { _id: 'mockUserId' } };
|
||||
const mockTaskInfo: any = {
|
||||
_id: new ObjectId(),
|
||||
creatorId: mockUserId.toString(),
|
||||
creatorId: 'mockUserId',
|
||||
};
|
||||
const mockDelRes = { modifiedCount: 1 };
|
||||
|
||||
@ -240,8 +237,6 @@ describe('DownloadTaskController', () => {
|
||||
|
||||
expect(downloadTaskService.deleteDownloadTask).toHaveBeenCalledWith({
|
||||
taskId: mockBody.taskId,
|
||||
operator: mockReq.user.username,
|
||||
operatorId: mockReq.user._id.toString(),
|
||||
});
|
||||
expect(result).toEqual({ code: 200, data: true });
|
||||
});
|
||||
|
@ -9,7 +9,7 @@ import { DataStatisticService } from '../services/dataStatistic.service';
|
||||
import { FileService } from 'src/modules/file/services/file.service';
|
||||
import { Logger } from 'src/logger';
|
||||
import { ObjectId } from 'mongodb';
|
||||
import { DOWNLOAD_TASK_STATUS } from 'src/enums/downloadTaskStatus';
|
||||
import { RECORD_STATUS } from 'src/enums';
|
||||
|
||||
describe('DownloadTaskService', () => {
|
||||
let service: DownloadTaskService;
|
||||
@ -93,7 +93,6 @@ describe('DownloadTaskService', () => {
|
||||
title: mockParams.responseSchema.title,
|
||||
},
|
||||
filename: expect.any(String),
|
||||
status: DOWNLOAD_TASK_STATUS.WAITING,
|
||||
});
|
||||
expect(downloadTaskRepository.save).toHaveBeenCalled();
|
||||
expect(result).toEqual(mockTaskId);
|
||||
@ -119,11 +118,10 @@ describe('DownloadTaskService', () => {
|
||||
expect(downloadTaskRepository.findAndCount).toHaveBeenCalledWith({
|
||||
where: {
|
||||
creatorId: mockCreatorId,
|
||||
isDeleted: { $ne: true },
|
||||
},
|
||||
take: 10,
|
||||
skip: 0,
|
||||
order: { createdAt: -1 },
|
||||
order: { createDate: -1 },
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
@ -162,84 +160,32 @@ describe('DownloadTaskService', () => {
|
||||
});
|
||||
|
||||
describe('deleteDownloadTask', () => {
|
||||
it('should mark task as deleted and set deletedAt', async () => {
|
||||
it('should update task status to REMOVED', async () => {
|
||||
const mockTaskId = new ObjectId().toString();
|
||||
const mockOperator = 'operatorName';
|
||||
const mockOperatorId = 'operatorId1';
|
||||
const mockUpdateResult = { matchedCount: 1 };
|
||||
|
||||
jest
|
||||
.spyOn(downloadTaskRepository, 'updateOne')
|
||||
.mockResolvedValue(mockUpdateResult as any);
|
||||
|
||||
const result = await service.deleteDownloadTask({
|
||||
taskId: mockTaskId,
|
||||
operator: mockOperator,
|
||||
operatorId: mockOperatorId,
|
||||
});
|
||||
const result = await service.deleteDownloadTask({ taskId: mockTaskId });
|
||||
|
||||
expect(downloadTaskRepository.updateOne).toHaveBeenCalledWith(
|
||||
{ _id: new ObjectId(mockTaskId) },
|
||||
{
|
||||
_id: new ObjectId(mockTaskId),
|
||||
'curStatus.status': { $ne: RECORD_STATUS.REMOVED },
|
||||
},
|
||||
{
|
||||
$set: {
|
||||
isDeleted: true,
|
||||
operator: mockOperator,
|
||||
operatorId: mockOperatorId,
|
||||
deletedAt: expect.any(Date),
|
||||
curStatus: {
|
||||
status: RECORD_STATUS.REMOVED,
|
||||
date: expect.any(Number),
|
||||
},
|
||||
},
|
||||
$push: { statusList: expect.any(Object) },
|
||||
},
|
||||
);
|
||||
expect(result).toEqual(mockUpdateResult);
|
||||
});
|
||||
});
|
||||
|
||||
describe('processDownloadTask', () => {
|
||||
it('should push task to queue and execute if not executing', async () => {
|
||||
const mockTaskId = new ObjectId().toString();
|
||||
jest.spyOn(service, 'executeTask').mockImplementation(jest.fn());
|
||||
|
||||
service.processDownloadTask({ taskId: mockTaskId });
|
||||
|
||||
expect(DownloadTaskService.taskList).toContain(mockTaskId);
|
||||
expect(service.executeTask).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should handle already executing case', async () => {
|
||||
const mockTaskId = new ObjectId().toString();
|
||||
DownloadTaskService.isExecuting = true;
|
||||
jest.spyOn(service, 'executeTask').mockImplementation(jest.fn());
|
||||
|
||||
service.processDownloadTask({ taskId: mockTaskId });
|
||||
|
||||
expect(DownloadTaskService.taskList).toContain(mockTaskId);
|
||||
expect(service.executeTask).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('executeTask', () => {
|
||||
it('should process and execute tasks in queue', async () => {
|
||||
const mockTaskId = new ObjectId().toString();
|
||||
DownloadTaskService.taskList.push(mockTaskId);
|
||||
|
||||
jest.spyOn(service, 'getDownloadTaskById').mockResolvedValue({
|
||||
_id: new ObjectId(mockTaskId),
|
||||
isDeleted: false,
|
||||
} as any);
|
||||
|
||||
jest.spyOn(service, 'handleDownloadTask').mockResolvedValue(undefined);
|
||||
|
||||
await service.executeTask();
|
||||
|
||||
expect(service.getDownloadTaskById).toHaveBeenCalledWith({
|
||||
taskId: mockTaskId,
|
||||
});
|
||||
expect(service.handleDownloadTask).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should stop executing when queue is empty', async () => {
|
||||
DownloadTaskService.taskList = [];
|
||||
await service.executeTask();
|
||||
expect(DownloadTaskService.isExecuting).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -14,8 +14,8 @@ export const mockSensitiveResponseSchema: ResponseSchema = {
|
||||
date: 1710399368439,
|
||||
},
|
||||
],
|
||||
createdAt: 1710399368440,
|
||||
updatedAt: 1710399368440,
|
||||
createDate: 1710399368440,
|
||||
updateDate: 1710399368440,
|
||||
title: '加密全流程',
|
||||
surveyPath: 'EBzdmnSp',
|
||||
code: {
|
||||
@ -71,6 +71,11 @@ export const mockSensitiveResponseSchema: ResponseSchema = {
|
||||
is_again: true,
|
||||
again_text: '确认要提交吗?',
|
||||
},
|
||||
jumpConfig: {
|
||||
type: 'link',
|
||||
link: '',
|
||||
buttonText: '',
|
||||
},
|
||||
},
|
||||
dataConf: {
|
||||
dataList: [
|
||||
@ -365,6 +370,11 @@ export const mockResponseSchema: ResponseSchema = {
|
||||
is_again: true,
|
||||
again_text: '确认要提交吗?',
|
||||
},
|
||||
jumpConfig: {
|
||||
type: 'link',
|
||||
link: '',
|
||||
buttonText: '',
|
||||
},
|
||||
},
|
||||
dataConf: {
|
||||
dataList: [
|
||||
@ -654,6 +664,6 @@ export const mockResponseSchema: ResponseSchema = {
|
||||
},
|
||||
},
|
||||
pageId: '65afc62904d5db18534c0f78',
|
||||
createdAt: 1710340841289,
|
||||
updatedAt: 1710340841289.0,
|
||||
createDate: 1710340841289,
|
||||
updateDate: 1710340841289.0,
|
||||
} as unknown as ResponseSchema;
|
||||
|
@ -1,144 +0,0 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { MongoRepository } from 'typeorm';
|
||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||
import { SessionService } from '../services/session.service';
|
||||
import { Session } from 'src/models/session.entity';
|
||||
import { ObjectId } from 'mongodb';
|
||||
import { SESSION_STATUS } from 'src/enums/surveySessionStatus';
|
||||
|
||||
describe('SessionService', () => {
|
||||
let service: SessionService;
|
||||
let repository: MongoRepository<Session>;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [
|
||||
SessionService,
|
||||
{
|
||||
provide: getRepositoryToken(Session),
|
||||
useClass: MongoRepository,
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
service = module.get<SessionService>(SessionService);
|
||||
repository = module.get<MongoRepository<Session>>(
|
||||
getRepositoryToken(Session),
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('create', () => {
|
||||
it('should create and save a new session', async () => {
|
||||
const mockSession = {
|
||||
surveyId: 'survey123',
|
||||
userId: 'user123',
|
||||
status: SESSION_STATUS.DEACTIVATED,
|
||||
};
|
||||
|
||||
const createdSession: any = { ...mockSession, _id: new ObjectId() };
|
||||
jest.spyOn(repository, 'create').mockReturnValue(createdSession);
|
||||
jest.spyOn(repository, 'save').mockResolvedValue(createdSession);
|
||||
|
||||
const result = await service.create({
|
||||
surveyId: mockSession.surveyId,
|
||||
userId: mockSession.userId,
|
||||
});
|
||||
|
||||
expect(result).toEqual(createdSession);
|
||||
expect(repository.create).toHaveBeenCalledWith(mockSession);
|
||||
expect(repository.save).toHaveBeenCalledWith(createdSession);
|
||||
});
|
||||
});
|
||||
|
||||
describe('findOne', () => {
|
||||
it('should find a session by id', async () => {
|
||||
const sessionId = '65afc62904d5db18534c0f78';
|
||||
const foundSession = {
|
||||
_id: new ObjectId(sessionId),
|
||||
surveyId: 'survey123',
|
||||
userId: 'user123',
|
||||
status: SESSION_STATUS.ACTIVATED,
|
||||
};
|
||||
|
||||
jest
|
||||
.spyOn(repository, 'findOne')
|
||||
.mockResolvedValue(foundSession as Session);
|
||||
|
||||
const result = await service.findOne(sessionId);
|
||||
|
||||
expect(result).toEqual(foundSession);
|
||||
expect(repository.findOne).toHaveBeenCalledWith({
|
||||
where: { _id: new ObjectId(sessionId) },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('findLatestEditingOne', () => {
|
||||
it('should find the latest editing session for a survey', async () => {
|
||||
const surveyId = 'survey123';
|
||||
const latestSession = {
|
||||
_id: new ObjectId(),
|
||||
surveyId: surveyId,
|
||||
userId: 'user123',
|
||||
status: SESSION_STATUS.ACTIVATED,
|
||||
};
|
||||
|
||||
jest
|
||||
.spyOn(repository, 'findOne')
|
||||
.mockResolvedValue(latestSession as Session);
|
||||
|
||||
const result = await service.findLatestEditingOne({ surveyId });
|
||||
|
||||
expect(result).toEqual(latestSession);
|
||||
expect(repository.findOne).toHaveBeenCalledWith({
|
||||
where: {
|
||||
surveyId,
|
||||
status: SESSION_STATUS.ACTIVATED,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateSessionToEditing', () => {
|
||||
it('should update a session to editing and deactivate other sessions', async () => {
|
||||
const sessionId = '65afc62904d5db18534c0f78';
|
||||
const surveyId = 'survey123';
|
||||
|
||||
const updateResult: any = { affected: 1 };
|
||||
const updateManyResult = { modifiedCount: 1 };
|
||||
|
||||
jest.spyOn(repository, 'update').mockResolvedValue(updateResult);
|
||||
jest.spyOn(repository, 'updateMany').mockResolvedValue(updateManyResult);
|
||||
|
||||
const result = await service.updateSessionToEditing({
|
||||
sessionId,
|
||||
surveyId,
|
||||
});
|
||||
|
||||
expect(result).toEqual([updateResult, updateManyResult]);
|
||||
expect(repository.update).toHaveBeenCalledWith(
|
||||
{ _id: new ObjectId(sessionId) },
|
||||
{
|
||||
status: SESSION_STATUS.ACTIVATED,
|
||||
updatedAt: expect.any(Date),
|
||||
},
|
||||
);
|
||||
expect(repository.updateMany).toHaveBeenCalledWith(
|
||||
{
|
||||
surveyId,
|
||||
_id: { $ne: new ObjectId(sessionId) },
|
||||
},
|
||||
{
|
||||
$set: {
|
||||
status: SESSION_STATUS.DEACTIVATED,
|
||||
updatedAt: expect.any(Date),
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
@ -5,12 +5,13 @@ import { SurveyConfService } from '../services/surveyConf.service';
|
||||
import { ResponseSchemaService } from '../../surveyResponse/services/responseScheme.service';
|
||||
import { ContentSecurityService } from '../services/contentSecurity.service';
|
||||
import { SurveyHistoryService } from '../services/surveyHistory.service';
|
||||
import { CounterService } from '../../surveyResponse/services/counter.service';
|
||||
import { SessionService } from '../services/session.service';
|
||||
import { UserService } from '../../auth/services/user.service';
|
||||
import { ObjectId } from 'mongodb';
|
||||
import { SurveyMeta } from 'src/models/surveyMeta.entity';
|
||||
import { SurveyConf } from 'src/models/surveyConf.entity';
|
||||
import { Logger } from 'src/logger';
|
||||
import { HttpException } from 'src/exceptions/httpException';
|
||||
import { Authentication } from 'src/guards/authentication.guard';
|
||||
|
||||
jest.mock('../services/surveyMeta.service');
|
||||
jest.mock('../services/surveyConf.service');
|
||||
@ -18,7 +19,9 @@ jest.mock('../../surveyResponse/services/responseScheme.service');
|
||||
jest.mock('../services/contentSecurity.service');
|
||||
jest.mock('../services/surveyHistory.service');
|
||||
jest.mock('../services/session.service');
|
||||
jest.mock('../../surveyResponse/services/counter.service');
|
||||
jest.mock('../../auth/services/user.service');
|
||||
|
||||
jest.mock('src/guards/authentication.guard');
|
||||
jest.mock('src/guards/survey.guard');
|
||||
jest.mock('src/guards/workspace.guard');
|
||||
@ -28,17 +31,28 @@ describe('SurveyController', () => {
|
||||
let surveyMetaService: SurveyMetaService;
|
||||
let surveyConfService: SurveyConfService;
|
||||
let responseSchemaService: ResponseSchemaService;
|
||||
let surveyHistoryService: SurveyHistoryService;
|
||||
let sessionService: SessionService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [SurveyController],
|
||||
providers: [
|
||||
SurveyMetaService,
|
||||
SurveyConfService,
|
||||
{
|
||||
provide: SurveyConfService,
|
||||
useValue: {
|
||||
getSurveyConfBySurveyId: jest.fn(),
|
||||
getSurveyContentByCode: jest.fn(),
|
||||
createSurveyConf: jest.fn(),
|
||||
saveSurveyConf: jest.fn(),
|
||||
},
|
||||
},
|
||||
ResponseSchemaService,
|
||||
ContentSecurityService,
|
||||
SurveyHistoryService,
|
||||
SessionService,
|
||||
CounterService,
|
||||
UserService,
|
||||
{
|
||||
provide: Logger,
|
||||
@ -47,12 +61,6 @@ describe('SurveyController', () => {
|
||||
info: jest.fn(),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: Authentication,
|
||||
useClass: jest.fn().mockImplementation(() => ({
|
||||
canActivate: () => true,
|
||||
})),
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
@ -62,6 +70,9 @@ describe('SurveyController', () => {
|
||||
responseSchemaService = module.get<ResponseSchemaService>(
|
||||
ResponseSchemaService,
|
||||
);
|
||||
surveyHistoryService =
|
||||
module.get<SurveyHistoryService>(SurveyHistoryService);
|
||||
sessionService = module.get<SessionService>(SessionService);
|
||||
});
|
||||
|
||||
describe('getBannerData', () => {
|
||||
@ -83,11 +94,12 @@ describe('SurveyController', () => {
|
||||
const newId = new ObjectId();
|
||||
jest.spyOn(surveyMetaService, 'createSurveyMeta').mockResolvedValue({
|
||||
_id: newId,
|
||||
} as any);
|
||||
} as SurveyMeta);
|
||||
|
||||
jest.spyOn(surveyConfService, 'createSurveyConf').mockResolvedValue({
|
||||
_id: new ObjectId(),
|
||||
} as any);
|
||||
pageId: newId.toString(),
|
||||
} as SurveyConf);
|
||||
|
||||
const result = await controller.createSurvey(surveyInfo, {
|
||||
user: { username: 'testUser', _id: new ObjectId() },
|
||||
@ -101,15 +113,13 @@ describe('SurveyController', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw an error if validation fails', async () => {
|
||||
const surveyInfo = {}; // Invalid data
|
||||
await expect(
|
||||
controller.createSurvey(surveyInfo as any, { user: {} }),
|
||||
).rejects.toThrow(HttpException);
|
||||
});
|
||||
|
||||
it('should create a new survey by copy', async () => {
|
||||
const existsSurveyId = new ObjectId();
|
||||
const existsSurveyMeta = {
|
||||
_id: existsSurveyId,
|
||||
surveyType: 'exam',
|
||||
owner: 'testUser',
|
||||
} as SurveyMeta;
|
||||
const params = {
|
||||
surveyType: 'normal',
|
||||
remark: '问卷调研',
|
||||
@ -118,14 +128,14 @@ describe('SurveyController', () => {
|
||||
createFrom: existsSurveyId.toString(),
|
||||
};
|
||||
|
||||
const request = {
|
||||
user: { username: 'testUser', _id: new ObjectId() },
|
||||
surveyMeta: { _id: existsSurveyId, surveyType: 'exam' },
|
||||
};
|
||||
|
||||
jest.spyOn(surveyMetaService, 'createSurveyMeta').mockResolvedValue({
|
||||
_id: new ObjectId(),
|
||||
} as any);
|
||||
} as SurveyMeta);
|
||||
|
||||
const request = {
|
||||
user: { username: 'testUser', _id: new ObjectId() },
|
||||
surveyMeta: existsSurveyMeta,
|
||||
};
|
||||
|
||||
const result = await controller.createSurvey(params, request);
|
||||
expect(result?.data?.id).toBeDefined();
|
||||
@ -135,30 +145,69 @@ describe('SurveyController', () => {
|
||||
describe('updateConf', () => {
|
||||
it('should update survey configuration', async () => {
|
||||
const surveyId = new ObjectId();
|
||||
const surveyMeta = {
|
||||
_id: surveyId,
|
||||
surveyType: 'exam',
|
||||
owner: 'testUser',
|
||||
} as SurveyMeta;
|
||||
|
||||
jest
|
||||
.spyOn(surveyConfService, 'saveSurveyConf')
|
||||
.mockResolvedValue(undefined);
|
||||
jest
|
||||
.spyOn(surveyHistoryService, 'addHistory')
|
||||
.mockResolvedValue(undefined);
|
||||
jest
|
||||
.spyOn(sessionService, 'findLatestEditingOne')
|
||||
.mockResolvedValue(null);
|
||||
jest
|
||||
.spyOn(sessionService, 'updateSessionToEditing')
|
||||
.mockResolvedValue(undefined);
|
||||
|
||||
const reqBody = {
|
||||
surveyId: surveyId.toString(),
|
||||
configData: {
|
||||
/* ... your config data here ... */
|
||||
bannerConf: {
|
||||
titleConfig: {},
|
||||
bannerConfig: {},
|
||||
},
|
||||
baseConf: {
|
||||
beginTime: '2024-01-23 21:59:05',
|
||||
endTime: '2034-01-23 21:59:05',
|
||||
},
|
||||
bottomConf: { logoImage: '/imgs/Logo.webp', logoImageWidth: '60%' },
|
||||
skinConf: {
|
||||
skinColor: '#4a4c5b',
|
||||
inputBgColor: '#ffffff',
|
||||
backgroundConf: {
|
||||
color: '#fff',
|
||||
type: 'color',
|
||||
image: '',
|
||||
},
|
||||
themeConf: {
|
||||
color: '#ffa600',
|
||||
},
|
||||
contentConf: {
|
||||
opacity: 100,
|
||||
},
|
||||
},
|
||||
submitConf: {},
|
||||
dataConf: {
|
||||
dataList: [],
|
||||
},
|
||||
},
|
||||
sessionId: 'mock-session-id',
|
||||
};
|
||||
|
||||
const result = await controller.updateConf(reqBody, {
|
||||
user: { username: 'testUser', _id: 'testUserId' },
|
||||
surveyMeta: { _id: surveyId },
|
||||
surveyMeta,
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
code: 200,
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw an error if validation fails', async () => {
|
||||
const reqBody = {}; // Invalid data
|
||||
await expect(
|
||||
controller.updateConf(reqBody, { user: {} }),
|
||||
).rejects.toThrow(HttpException);
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteSurvey', () => {
|
||||
@ -168,7 +217,7 @@ describe('SurveyController', () => {
|
||||
_id: surveyId,
|
||||
surveyType: 'exam',
|
||||
owner: 'testUser',
|
||||
};
|
||||
} as SurveyMeta;
|
||||
|
||||
jest
|
||||
.spyOn(surveyMetaService, 'deleteSurveyMeta')
|
||||
@ -178,10 +227,13 @@ describe('SurveyController', () => {
|
||||
.mockResolvedValue(undefined);
|
||||
|
||||
const result = await controller.deleteSurvey({
|
||||
user: { username: 'testUser' },
|
||||
surveyMeta,
|
||||
user: { username: 'testUser', _id: new ObjectId() },
|
||||
});
|
||||
expect(result).toEqual({ code: 200 });
|
||||
|
||||
expect(result).toEqual({
|
||||
code: 200,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -192,19 +244,23 @@ describe('SurveyController', () => {
|
||||
_id: surveyId,
|
||||
surveyType: 'exam',
|
||||
owner: 'testUser',
|
||||
};
|
||||
} as SurveyMeta;
|
||||
|
||||
jest
|
||||
.spyOn(surveyConfService, 'getSurveyConfBySurveyId')
|
||||
.mockResolvedValue({} as any);
|
||||
.mockResolvedValue({
|
||||
_id: new ObjectId(),
|
||||
pageId: surveyId.toString(),
|
||||
} as SurveyConf);
|
||||
|
||||
const request = {
|
||||
user: { username: 'testUser', _id: new ObjectId() },
|
||||
surveyMeta,
|
||||
};
|
||||
const result = await controller.getSurvey(
|
||||
{ surveyId: surveyId.toString() },
|
||||
{
|
||||
surveyMeta,
|
||||
user: { username: 'testUser', _id: new ObjectId() },
|
||||
},
|
||||
request,
|
||||
);
|
||||
|
||||
expect(result?.data?.surveyMetaRes).toBeDefined();
|
||||
expect(result?.data?.surveyConfRes).toBeDefined();
|
||||
});
|
||||
@ -217,77 +273,28 @@ describe('SurveyController', () => {
|
||||
_id: surveyId,
|
||||
surveyType: 'exam',
|
||||
owner: 'testUser',
|
||||
isDeleted: false,
|
||||
};
|
||||
} as SurveyMeta;
|
||||
|
||||
jest
|
||||
.spyOn(surveyConfService, 'getSurveyConfBySurveyId')
|
||||
.mockResolvedValue({
|
||||
_id: new ObjectId(),
|
||||
pageId: surveyId.toString(),
|
||||
code: {},
|
||||
} as any);
|
||||
} as SurveyConf);
|
||||
|
||||
jest
|
||||
.spyOn(surveyConfService, 'getSurveyContentByCode')
|
||||
.mockResolvedValue({ text: '' });
|
||||
jest
|
||||
.spyOn(surveyMetaService, 'publishSurveyMeta')
|
||||
.mockResolvedValue(undefined);
|
||||
|
||||
const result = await controller.publishSurvey(
|
||||
{ surveyId: surveyId.toString() },
|
||||
{ surveyMeta, user: { username: 'testUser', _id: new ObjectId() } },
|
||||
{
|
||||
user: { username: 'testUser', _id: new ObjectId() },
|
||||
surveyMeta,
|
||||
},
|
||||
);
|
||||
expect(result.code).toBe(200);
|
||||
});
|
||||
|
||||
it('should throw an error if the survey is deleted', async () => {
|
||||
const surveyId = new ObjectId();
|
||||
const surveyMeta = { _id: surveyId, isDeleted: true };
|
||||
|
||||
await expect(
|
||||
controller.publishSurvey(
|
||||
{ surveyId: surveyId.toString() },
|
||||
{ surveyMeta, user: { username: 'testUser' } },
|
||||
),
|
||||
).rejects.toThrow(HttpException);
|
||||
});
|
||||
});
|
||||
|
||||
// New tests for additional methods
|
||||
describe('pausingSurvey', () => {
|
||||
it('should pause the survey successfully', async () => {
|
||||
const surveyMeta = { surveyPath: 'some/path' };
|
||||
|
||||
jest
|
||||
.spyOn(surveyMetaService, 'pausingSurveyMeta')
|
||||
.mockResolvedValue(undefined);
|
||||
jest
|
||||
.spyOn(responseSchemaService, 'pausingResponseSchema')
|
||||
.mockResolvedValue(undefined);
|
||||
|
||||
const result = await controller.pausingSurvey({
|
||||
surveyMeta,
|
||||
user: { username: 'testUser' },
|
||||
});
|
||||
expect(result.code).toBe(200);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getPreviewSchema', () => {
|
||||
it('should get the preview schema successfully', async () => {
|
||||
const surveyId = new ObjectId();
|
||||
jest
|
||||
.spyOn(surveyConfService, 'getSurveyConfBySurveyId')
|
||||
.mockResolvedValue({} as any);
|
||||
jest.spyOn(surveyMetaService, 'getSurveyById').mockResolvedValue({
|
||||
title: 'Test Survey',
|
||||
surveyPath: 'some/path',
|
||||
} as any);
|
||||
|
||||
const result = await controller.getPreviewSchema({
|
||||
surveyPath: surveyId.toString(),
|
||||
});
|
||||
expect(result.code).toBe(200);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -121,9 +121,9 @@ describe('SurveyHistoryService', () => {
|
||||
},
|
||||
take: 100,
|
||||
order: {
|
||||
createdAt: -1,
|
||||
createDate: -1,
|
||||
},
|
||||
select: ['createdAt', 'operator', 'type', '_id'],
|
||||
select: ['createDate', 'operator', 'type', '_id'],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -59,25 +59,18 @@ describe('SurveyMetaController', () => {
|
||||
remark: '',
|
||||
};
|
||||
|
||||
const mockUser = {
|
||||
username: 'test-user',
|
||||
_id: new ObjectId(),
|
||||
};
|
||||
|
||||
const req = {
|
||||
user: mockUser,
|
||||
user: {
|
||||
username: 'test-user',
|
||||
},
|
||||
surveyMeta: survey,
|
||||
};
|
||||
|
||||
const result = await controller.updateMeta(reqBody, req);
|
||||
|
||||
expect(surveyMetaService.editSurveyMeta).toHaveBeenCalledWith({
|
||||
operator: mockUser.username,
|
||||
operatorId: mockUser._id.toString(),
|
||||
survey: {
|
||||
title: reqBody.title,
|
||||
remark: reqBody.remark,
|
||||
},
|
||||
title: reqBody.title,
|
||||
remark: reqBody.remark,
|
||||
});
|
||||
|
||||
expect(result).toEqual({ code: 200 });
|
||||
@ -123,8 +116,8 @@ describe('SurveyMetaController', () => {
|
||||
data: [
|
||||
{
|
||||
_id: new ObjectId(),
|
||||
createdAt: date,
|
||||
updatedAt: date,
|
||||
createDate: date,
|
||||
updateDate: date,
|
||||
curStatus: {
|
||||
date: date,
|
||||
},
|
||||
@ -145,7 +138,7 @@ describe('SurveyMetaController', () => {
|
||||
count: 10,
|
||||
data: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
createdAt: expect.stringMatching(
|
||||
createDate: expect.stringMatching(
|
||||
/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/,
|
||||
),
|
||||
curStatus: expect.objectContaining({
|
||||
@ -190,7 +183,7 @@ describe('SurveyMetaController', () => {
|
||||
condition: [{ field: 'surveyType', value: 'normal' }],
|
||||
},
|
||||
]),
|
||||
order: JSON.stringify([{ field: 'createdAt', value: -1 }]),
|
||||
order: JSON.stringify([{ field: 'createDate', value: -1 }]),
|
||||
};
|
||||
const userId = new ObjectId().toString();
|
||||
const req = {
|
||||
@ -210,7 +203,7 @@ describe('SurveyMetaController', () => {
|
||||
surveyIdList: [],
|
||||
userId,
|
||||
filter: { surveyType: 'normal', title: { $regex: 'hahah' } },
|
||||
order: { createdAt: -1 },
|
||||
order: { createDate: -1 },
|
||||
workspaceId: undefined,
|
||||
});
|
||||
});
|
||||
|
@ -2,10 +2,12 @@ import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { SurveyMetaService } from '../services/surveyMeta.service';
|
||||
import { MongoRepository } from 'typeorm';
|
||||
import { SurveyMeta } from 'src/models/surveyMeta.entity';
|
||||
import { PluginManagerProvider } from 'src/securityPlugin/pluginManager.provider';
|
||||
import { PluginManager } from 'src/securityPlugin/pluginManager';
|
||||
import { RECORD_STATUS, RECORD_SUB_STATUS } from 'src/enums';
|
||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||
import { HttpException } from 'src/exceptions/httpException';
|
||||
import { RECORD_STATUS, RECORD_SUB_STATUS } from 'src/enums';
|
||||
import { SurveyUtilPlugin } from 'src/securityPlugin/surveyUtilPlugin';
|
||||
import { ObjectId } from 'mongodb';
|
||||
|
||||
describe('SurveyMetaService', () => {
|
||||
@ -24,11 +26,10 @@ describe('SurveyMetaService', () => {
|
||||
count: jest.fn(),
|
||||
create: jest.fn(),
|
||||
save: jest.fn(),
|
||||
updateOne: jest.fn(),
|
||||
findAndCount: jest.fn(),
|
||||
},
|
||||
},
|
||||
PluginManager,
|
||||
PluginManagerProvider,
|
||||
],
|
||||
}).compile();
|
||||
|
||||
@ -37,18 +38,18 @@ describe('SurveyMetaService', () => {
|
||||
getRepositoryToken(SurveyMeta),
|
||||
);
|
||||
pluginManager = module.get<PluginManager>(PluginManager);
|
||||
pluginManager.registerPlugin(new SurveyUtilPlugin());
|
||||
});
|
||||
|
||||
describe('getNewSurveyPath', () => {
|
||||
it('should generate a new survey path', async () => {
|
||||
jest.spyOn(pluginManager, 'triggerHook').mockResolvedValueOnce('path1');
|
||||
jest.spyOn(surveyRepository, 'count').mockResolvedValueOnce(1);
|
||||
jest.spyOn(surveyRepository, 'count').mockResolvedValueOnce(0);
|
||||
|
||||
const surveyPath = await service.getNewSurveyPath();
|
||||
|
||||
expect(surveyPath).toBe('path1');
|
||||
expect(pluginManager.triggerHook).toHaveBeenCalledTimes(1);
|
||||
expect(surveyRepository.count).toHaveBeenCalledTimes(1);
|
||||
expect(typeof surveyPath).toBe('string');
|
||||
expect(surveyRepository.count).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
@ -62,11 +63,14 @@ describe('SurveyMetaService', () => {
|
||||
userId: new ObjectId().toString(),
|
||||
createMethod: '',
|
||||
createFrom: '',
|
||||
workspaceId: 'workspace1',
|
||||
};
|
||||
const newSurvey = new SurveyMeta();
|
||||
|
||||
jest.spyOn(service, 'getNewSurveyPath').mockResolvedValue('path1');
|
||||
const mockedSurveyPath = 'mockedSurveyPath';
|
||||
jest
|
||||
.spyOn(service, 'getNewSurveyPath')
|
||||
.mockResolvedValue(mockedSurveyPath);
|
||||
|
||||
jest
|
||||
.spyOn(surveyRepository, 'create')
|
||||
.mockImplementation(() => newSurvey);
|
||||
@ -78,118 +82,97 @@ describe('SurveyMetaService', () => {
|
||||
title: params.title,
|
||||
remark: params.remark,
|
||||
surveyType: params.surveyType,
|
||||
surveyPath: 'path1',
|
||||
surveyPath: mockedSurveyPath,
|
||||
creator: params.username,
|
||||
creatorId: params.userId,
|
||||
owner: params.username,
|
||||
ownerId: params.userId,
|
||||
owner: params.username,
|
||||
createMethod: params.createMethod,
|
||||
createFrom: params.createFrom,
|
||||
workspaceId: params.workspaceId,
|
||||
});
|
||||
expect(surveyRepository.save).toHaveBeenCalledWith(newSurvey);
|
||||
expect(result).toEqual(newSurvey);
|
||||
});
|
||||
});
|
||||
|
||||
describe('pausingSurveyMeta', () => {
|
||||
it('should throw an exception if survey is in NEW status', async () => {
|
||||
const survey = new SurveyMeta();
|
||||
survey.curStatus = { status: RECORD_STATUS.NEW, date: Date.now() };
|
||||
|
||||
await expect(service.pausingSurveyMeta(survey)).rejects.toThrow(
|
||||
HttpException,
|
||||
);
|
||||
});
|
||||
|
||||
it('should pause a survey and update subStatus', async () => {
|
||||
const survey = new SurveyMeta();
|
||||
survey.curStatus = { status: RECORD_STATUS.PUBLISHED, date: Date.now() };
|
||||
survey.statusList = [];
|
||||
|
||||
jest.spyOn(surveyRepository, 'save').mockResolvedValue(survey);
|
||||
|
||||
const result = await service.pausingSurveyMeta(survey);
|
||||
|
||||
expect(survey.subStatus.status).toBe(RECORD_SUB_STATUS.PAUSING);
|
||||
expect(survey.statusList.length).toBe(1);
|
||||
expect(survey.statusList[0].status).toBe(RECORD_SUB_STATUS.PAUSING);
|
||||
expect(surveyRepository.save).toHaveBeenCalledWith(survey);
|
||||
expect(result).toEqual(survey);
|
||||
});
|
||||
});
|
||||
|
||||
describe('editSurveyMeta', () => {
|
||||
it('should edit a survey meta and return it', async () => {
|
||||
it('should edit a survey meta and return it if in NEW or EDITING status', async () => {
|
||||
const survey = new SurveyMeta();
|
||||
survey.curStatus = { status: RECORD_STATUS.PUBLISHED, date: Date.now() };
|
||||
survey.subStatus = {
|
||||
status: RECORD_SUB_STATUS.DEFAULT,
|
||||
date: Date.now(),
|
||||
};
|
||||
survey.statusList = [];
|
||||
|
||||
const operator = 'editor';
|
||||
const operatorId = 'editorId';
|
||||
|
||||
jest.spyOn(surveyRepository, 'save').mockResolvedValue(survey);
|
||||
|
||||
const result = await service.editSurveyMeta({
|
||||
survey,
|
||||
operator,
|
||||
operatorId,
|
||||
});
|
||||
const result = await service.editSurveyMeta(survey);
|
||||
|
||||
expect(survey.curStatus.status).toBe(RECORD_STATUS.EDITING);
|
||||
expect(survey.curStatus.status).toEqual(RECORD_STATUS.EDITING);
|
||||
expect(survey.statusList.length).toBe(1);
|
||||
expect(survey.statusList[0].status).toBe(RECORD_STATUS.EDITING);
|
||||
expect(survey.operator).toBe(operator);
|
||||
expect(survey.operatorId).toBe(operatorId);
|
||||
expect(survey.statusList[0].status).toEqual(RECORD_STATUS.EDITING);
|
||||
expect(surveyRepository.save).toHaveBeenCalledWith(survey);
|
||||
expect(result).toEqual(survey);
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteSurveyMeta', () => {
|
||||
it('should mark a survey as deleted', async () => {
|
||||
const surveyId = new ObjectId().toString();
|
||||
const operator = 'deleter';
|
||||
const operatorId = 'deleterId';
|
||||
it('should delete survey meta and update status', async () => {
|
||||
// 准备假的SurveyMeta对象
|
||||
const survey = new SurveyMeta();
|
||||
survey.curStatus = { status: RECORD_STATUS.NEW, date: Date.now() };
|
||||
survey.subStatus = {
|
||||
status: RECORD_SUB_STATUS.DEFAULT,
|
||||
date: Date.now(),
|
||||
};
|
||||
survey.statusList = [];
|
||||
|
||||
jest.spyOn(surveyRepository, 'updateOne').mockResolvedValue({
|
||||
matchedCount: 1,
|
||||
modifiedCount: 1,
|
||||
acknowledged: true,
|
||||
});
|
||||
// 模拟save方法
|
||||
jest.spyOn(surveyRepository, 'save').mockResolvedValue(survey);
|
||||
|
||||
const result = await service.deleteSurveyMeta({
|
||||
surveyId,
|
||||
operator,
|
||||
operatorId,
|
||||
});
|
||||
// 调用要测试的方法
|
||||
const result = await service.deleteSurveyMeta(survey);
|
||||
|
||||
expect(surveyRepository.updateOne).toHaveBeenCalledWith(
|
||||
{ _id: new ObjectId(surveyId) },
|
||||
{
|
||||
$set: {
|
||||
isDeleted: true,
|
||||
operator,
|
||||
operatorId,
|
||||
deletedAt: expect.any(Date),
|
||||
},
|
||||
},
|
||||
// 验证结果
|
||||
expect(result).toBe(survey);
|
||||
expect(survey.subStatus.status).toBe(RECORD_STATUS.REMOVED);
|
||||
expect(survey.statusList.length).toBe(1);
|
||||
expect(survey.statusList[0].status).toBe(RECORD_STATUS.REMOVED);
|
||||
expect(surveyRepository.save).toHaveBeenCalledTimes(1);
|
||||
expect(surveyRepository.save).toHaveBeenCalledWith(survey);
|
||||
});
|
||||
|
||||
it('should throw exception when survey is already removed', async () => {
|
||||
// 准备假的SurveyMeta对象,其状态已设置为REMOVED
|
||||
const survey = new SurveyMeta();
|
||||
survey.curStatus = {
|
||||
status: RECORD_STATUS.REMOVED,
|
||||
date: Date.now(),
|
||||
};
|
||||
|
||||
// 调用要测试的方法并期待异常
|
||||
await expect(service.deleteSurveyMeta(survey)).rejects.toThrow(
|
||||
HttpException,
|
||||
);
|
||||
expect(result.matchedCount).toBe(1);
|
||||
|
||||
// 验证save方法没有被调用
|
||||
expect(surveyRepository.save).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSurveyMetaList', () => {
|
||||
it('should return a list of survey metadata', async () => {
|
||||
// 准备模拟数据
|
||||
const mockData = [
|
||||
{ _id: 1, title: 'Survey 1' },
|
||||
{ _id: 2, title: 'Survey 2' },
|
||||
] as unknown as Array<SurveyMeta>;
|
||||
const mockCount = 1;
|
||||
const mockCount = 2;
|
||||
|
||||
jest
|
||||
.spyOn(surveyRepository, 'findAndCount')
|
||||
.mockResolvedValue([mockData, mockCount]);
|
||||
|
||||
// 调用方法并检查返回值
|
||||
const condition = {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
@ -198,47 +181,44 @@ describe('SurveyMetaService', () => {
|
||||
filter: {},
|
||||
order: {},
|
||||
};
|
||||
|
||||
const result = await service.getSurveyMetaList(condition);
|
||||
|
||||
// 验证返回值
|
||||
expect(result).toEqual({ data: mockData, count: mockCount });
|
||||
// 验证repository方法被正确调用
|
||||
expect(surveyRepository.findAndCount).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('publishSurveyMeta', () => {
|
||||
it('should publish a survey and update curStatus', async () => {
|
||||
const surveyMeta = new SurveyMeta();
|
||||
surveyMeta.statusList = [];
|
||||
it('should publish a survey meta and add status to statusList', async () => {
|
||||
// 准备模拟数据
|
||||
const surveyMeta = {
|
||||
id: 1,
|
||||
title: 'Test Survey',
|
||||
statusList: [],
|
||||
} as unknown as SurveyMeta;
|
||||
const savedSurveyMeta = {
|
||||
...surveyMeta,
|
||||
curStatus: {
|
||||
status: RECORD_STATUS.PUBLISHED,
|
||||
date: expect.any(Number),
|
||||
},
|
||||
subStatus: {
|
||||
status: RECORD_SUB_STATUS.DEFAULT,
|
||||
date: expect.any(Number),
|
||||
},
|
||||
} as unknown as SurveyMeta;
|
||||
|
||||
jest.spyOn(surveyRepository, 'save').mockResolvedValue(surveyMeta);
|
||||
jest.spyOn(surveyRepository, 'save').mockResolvedValue(savedSurveyMeta);
|
||||
|
||||
// 调用方法并检查返回值
|
||||
const result = await service.publishSurveyMeta({ surveyMeta });
|
||||
|
||||
expect(surveyMeta.curStatus.status).toBe(RECORD_STATUS.PUBLISHED);
|
||||
expect(surveyMeta.statusList.length).toBe(1);
|
||||
expect(surveyMeta.statusList[0].status).toBe(RECORD_STATUS.PUBLISHED);
|
||||
expect(surveyRepository.save).toHaveBeenCalledWith(surveyMeta);
|
||||
expect(result).toEqual(surveyMeta);
|
||||
});
|
||||
});
|
||||
|
||||
describe('countSurveyMetaByWorkspaceId', () => {
|
||||
it('should return the count of surveys in a workspace', async () => {
|
||||
const workspaceId = 'workspace1';
|
||||
const mockCount = 5;
|
||||
|
||||
jest.spyOn(surveyRepository, 'count').mockResolvedValue(mockCount);
|
||||
|
||||
const result = await service.countSurveyMetaByWorkspaceId({
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
expect(result).toBe(mockCount);
|
||||
expect(surveyRepository.count).toHaveBeenCalledWith({
|
||||
workspaceId,
|
||||
isDeleted: { $ne: true },
|
||||
});
|
||||
// 验证返回值
|
||||
expect(result).toEqual(savedSurveyMeta);
|
||||
// 验证repository方法被正确调用
|
||||
expect(surveyRepository.save).toHaveBeenCalledWith(savedSurveyMeta);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -17,8 +17,8 @@ import { DOWNLOAD_TASK_STATUS } from 'src/enums/downloadTaskStatus';
|
||||
|
||||
@Injectable()
|
||||
export class DownloadTaskService {
|
||||
static taskList: Array<any> = [];
|
||||
static isExecuting: boolean = false;
|
||||
private static taskList: Array<any> = [];
|
||||
private static isExecuting: boolean = false;
|
||||
|
||||
constructor(
|
||||
@InjectRepository(DownloadTask)
|
||||
@ -153,7 +153,7 @@ export class DownloadTaskService {
|
||||
}
|
||||
}
|
||||
|
||||
async handleDownloadTask({ taskInfo }) {
|
||||
private async handleDownloadTask({ taskInfo }) {
|
||||
try {
|
||||
// 更新任务状态为计算中
|
||||
const updateRes = await this.downloadTaskRepository.updateOne(
|
||||
|
@ -39,8 +39,8 @@
|
||||
"showSpliter": true,
|
||||
"placeholder": "",
|
||||
"isRequired": true,
|
||||
"starMin": "",
|
||||
"starMax": "",
|
||||
"min": "",
|
||||
"max": "",
|
||||
"type": "radio-star",
|
||||
"title": "标题2"
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ describe('ClientEncryptService', () => {
|
||||
save: jest.fn(),
|
||||
findOne: jest.fn(),
|
||||
updateOne: jest.fn(),
|
||||
deleteOne: jest.fn(),
|
||||
},
|
||||
},
|
||||
],
|
||||
@ -106,13 +105,11 @@ describe('ClientEncryptService', () => {
|
||||
describe('deleteEncryptInfo', () => {
|
||||
it('should delete encrypt info by id', async () => {
|
||||
const id = new ObjectId().toHexString();
|
||||
const deleteResult = { matchedCount: 1, modifiedCount: 1 };
|
||||
jest
|
||||
.spyOn(repository, 'deleteOne')
|
||||
.mockResolvedValue(deleteResult as any);
|
||||
const updateResult = { matchedCount: 1, modifiedCount: 1 };
|
||||
jest.spyOn(repository, 'updateOne').mockResolvedValue(updateResult);
|
||||
|
||||
const result = await service.deleteEncryptInfo(id);
|
||||
expect(result).toEqual(deleteResult);
|
||||
expect(result).toEqual(updateResult);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -50,7 +50,6 @@ describe('CounterService', () => {
|
||||
surveyPath: 'testPath',
|
||||
type: 'testType',
|
||||
data,
|
||||
updatedAt: expect.any(Date),
|
||||
},
|
||||
},
|
||||
{ upsert: true },
|
||||
|
@ -18,8 +18,8 @@ export const mockResponseSchema: ResponseSchema = {
|
||||
date: 1710399368439,
|
||||
},
|
||||
],
|
||||
createdAt: 1710399368440,
|
||||
updatedAt: 1710399368440,
|
||||
createDate: 1710399368440,
|
||||
updateDate: 1710399368440,
|
||||
title: '加密全流程',
|
||||
surveyPath: 'EBzdmnSp',
|
||||
code: {
|
||||
@ -75,6 +75,11 @@ export const mockResponseSchema: ResponseSchema = {
|
||||
is_again: true,
|
||||
again_text: '确认要提交吗?',
|
||||
},
|
||||
jumpConfig: {
|
||||
type: 'link',
|
||||
link: '',
|
||||
buttonText: '',
|
||||
},
|
||||
},
|
||||
dataConf: {
|
||||
dataList: [
|
||||
|
@ -3,28 +3,27 @@ import { ResponseSchemaController } from '../controllers/responseSchema.controll
|
||||
import { ResponseSchemaService } from '../services/responseScheme.service';
|
||||
import { HttpException } from 'src/exceptions/httpException';
|
||||
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
||||
import { RECORD_SUB_STATUS } from 'src/enums';
|
||||
import { RECORD_STATUS, RECORD_SUB_STATUS } from 'src/enums';
|
||||
|
||||
import { ResponseSchema } from 'src/models/responseSchema.entity';
|
||||
import { Logger } from 'src/logger';
|
||||
import { UserService } from 'src/modules/auth/services/user.service';
|
||||
import { WorkspaceMemberService } from 'src/modules/workspace/services/workspaceMember.service';
|
||||
import { AuthService } from 'src/modules/auth/services/auth.service';
|
||||
import { SurveyNotFoundException } from 'src/exceptions/surveyNotFoundException';
|
||||
|
||||
jest.mock('../services/responseScheme.service');
|
||||
jest.mock('src/modules/auth/services/user.service');
|
||||
jest.mock('src/modules/workspace/services/workspaceMember.service');
|
||||
|
||||
describe('ResponseSchemaController', () => {
|
||||
let controller: ResponseSchemaController;
|
||||
let responseSchemaService: ResponseSchemaService;
|
||||
let userService: UserService;
|
||||
let workspaceMemberService: WorkspaceMemberService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [ResponseSchemaController],
|
||||
providers: [
|
||||
ResponseSchemaService,
|
||||
AuthService,
|
||||
{
|
||||
provide: Logger,
|
||||
useValue: {
|
||||
@ -43,6 +42,12 @@ describe('ResponseSchemaController', () => {
|
||||
findAllByUserId: jest.fn(),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: AuthService,
|
||||
useValue: {
|
||||
create: jest.fn(),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: Logger,
|
||||
useValue: {
|
||||
@ -56,10 +61,6 @@ describe('ResponseSchemaController', () => {
|
||||
responseSchemaService = module.get<ResponseSchemaService>(
|
||||
ResponseSchemaService,
|
||||
);
|
||||
userService = module.get<UserService>(UserService);
|
||||
workspaceMemberService = module.get<WorkspaceMemberService>(
|
||||
WorkspaceMemberService,
|
||||
);
|
||||
});
|
||||
|
||||
describe('getSchema', () => {
|
||||
@ -67,20 +68,13 @@ describe('ResponseSchemaController', () => {
|
||||
const mockQueryInfo = { surveyPath: 'validSurveyPath' };
|
||||
const mockResponseSchema = {
|
||||
surveyPath: 'testSurveyPath',
|
||||
curStatus: { status: 'published', date: Date.now() },
|
||||
curStatus: { status: RECORD_STATUS.PUBLISHED, date: Date.now() },
|
||||
subStatus: { status: RECORD_SUB_STATUS.DEFAULT, date: Date.now() },
|
||||
code: {
|
||||
baseConf: {
|
||||
passwordSwitch: false,
|
||||
password: null,
|
||||
whitelist: [],
|
||||
},
|
||||
},
|
||||
} as ResponseSchema;
|
||||
|
||||
jest
|
||||
.spyOn(responseSchemaService, 'getResponseSchemaByPath')
|
||||
.mockResolvedValue(mockResponseSchema);
|
||||
.mockResolvedValue(Promise.resolve(mockResponseSchema));
|
||||
|
||||
const result = await controller.getSchema(mockQueryInfo);
|
||||
|
||||
@ -104,180 +98,168 @@ describe('ResponseSchemaController', () => {
|
||||
jest
|
||||
.spyOn(responseSchemaService, 'getResponseSchemaByPath')
|
||||
.mockResolvedValue({
|
||||
isDeleted: true,
|
||||
subStatus: { status: RECORD_SUB_STATUS.REMOVED },
|
||||
} as ResponseSchema);
|
||||
|
||||
await expect(controller.getSchema(mockQueryInfo)).rejects.toThrow(
|
||||
new HttpException(
|
||||
'问卷不存在或已删除',
|
||||
EXCEPTION_CODE.RESPONSE_SCHEMA_REMOVED,
|
||||
),
|
||||
new HttpException('问卷已删除', EXCEPTION_CODE.RESPONSE_SCHEMA_REMOVED),
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw HttpException with RESPONSE_PAUSING code when survey is paused', async () => {
|
||||
const mockQueryInfo = { surveyPath: 'pausedSurveyPath' };
|
||||
|
||||
jest
|
||||
.spyOn(responseSchemaService, 'getResponseSchemaByPath')
|
||||
.mockResolvedValue({
|
||||
curStatus: { status: 'published' },
|
||||
subStatus: { status: RECORD_SUB_STATUS.PAUSING },
|
||||
} as ResponseSchema);
|
||||
|
||||
await expect(controller.getSchema(mockQueryInfo)).rejects.toThrow(
|
||||
new HttpException('该问卷已暂停回收', EXCEPTION_CODE.RESPONSE_PAUSING),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('whitelistValidate', () => {
|
||||
it('should throw HttpException when parameters are invalid', async () => {
|
||||
const surveyPath = 'testSurveyPath';
|
||||
const body = { password: 1 };
|
||||
|
||||
await expect(
|
||||
controller.whitelistValidate(surveyPath, body),
|
||||
).rejects.toThrow(HttpException);
|
||||
});
|
||||
|
||||
it('should throw SurveyNotFoundException when survey is removed', async () => {
|
||||
const surveyPath = 'removedSurveyPath';
|
||||
it('whitelistValidate should throw SurveyNotFoundException when survey is removed', async () => {
|
||||
const surveyPath = '';
|
||||
jest
|
||||
.spyOn(responseSchemaService, 'getResponseSchemaByPath')
|
||||
.mockResolvedValue(null);
|
||||
|
||||
await expect(
|
||||
controller.whitelistValidate(surveyPath, { password: '123456' }),
|
||||
controller.whitelistValidate(surveyPath, {
|
||||
password: '123456',
|
||||
}),
|
||||
).rejects.toThrow(new SurveyNotFoundException('该问卷不存在,无法提交'));
|
||||
});
|
||||
|
||||
it('should throw HttpException when password is incorrect', async () => {
|
||||
const surveyPath = 'testSurveyPath';
|
||||
const mockSchema = {
|
||||
code: {
|
||||
baseConf: {
|
||||
passwordSwitch: true,
|
||||
password: '123456',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
it('whitelistValidate should throw WHITELIST_ERROR code when password is incorrect', async () => {
|
||||
const surveyPath = '';
|
||||
jest
|
||||
.spyOn(responseSchemaService, 'getResponseSchemaByPath')
|
||||
.mockResolvedValue(mockSchema as any);
|
||||
|
||||
await expect(
|
||||
controller.whitelistValidate(surveyPath, { password: 'wrongPassword' }),
|
||||
).rejects.toThrow(
|
||||
new HttpException('密码验证失败', EXCEPTION_CODE.WHITELIST_ERROR),
|
||||
);
|
||||
});
|
||||
|
||||
it('should validate successfully when password is correct', async () => {
|
||||
const surveyPath = 'testSurveyPath';
|
||||
const mockSchema = {
|
||||
code: {
|
||||
baseConf: {
|
||||
passwordSwitch: true,
|
||||
password: '123456',
|
||||
whitelistType: 'CUSTOM',
|
||||
whitelist: ['allowed@example.com'],
|
||||
.mockResolvedValue({
|
||||
curStatus: {
|
||||
status: 'published',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
jest
|
||||
.spyOn(responseSchemaService, 'getResponseSchemaByPath')
|
||||
.mockResolvedValue(mockSchema as any);
|
||||
|
||||
const result = await controller.whitelistValidate(surveyPath, {
|
||||
password: '123456',
|
||||
whitelist: 'allowed@example.com',
|
||||
});
|
||||
expect(result).toEqual({ code: 200, data: null });
|
||||
});
|
||||
|
||||
it('should throw HttpException when whitelist value is not in CUSTOM whitelist', async () => {
|
||||
const surveyPath = 'testSurveyPath';
|
||||
const mockSchema = {
|
||||
code: {
|
||||
baseConf: {
|
||||
whitelistType: 'CUSTOM',
|
||||
whitelist: ['allowed@example.com'],
|
||||
subStatus: {
|
||||
status: '',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
jest
|
||||
.spyOn(responseSchemaService, 'getResponseSchemaByPath')
|
||||
.mockResolvedValue(mockSchema as any);
|
||||
|
||||
code: {
|
||||
baseConf: {
|
||||
passwordSwitch: true,
|
||||
password: '123456',
|
||||
},
|
||||
},
|
||||
} as ResponseSchema);
|
||||
await expect(
|
||||
controller.whitelistValidate(surveyPath, {
|
||||
password: '123456',
|
||||
whitelist: 'notAllowed@example.com',
|
||||
password: '123457',
|
||||
}),
|
||||
).rejects.toThrow(
|
||||
new HttpException('白名单验证失败', EXCEPTION_CODE.WHITELIST_ERROR),
|
||||
new HttpException('验证失败', EXCEPTION_CODE.WHITELIST_ERROR),
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw HttpException when user is not found in MEMBER whitelist', async () => {
|
||||
const surveyPath = 'testSurveyPath';
|
||||
const mockSchema = {
|
||||
code: {
|
||||
baseConf: {
|
||||
whitelistType: 'MEMBER',
|
||||
whitelist: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
it('whitelistValidate should be successfully', async () => {
|
||||
const surveyPath = 'test';
|
||||
jest
|
||||
.spyOn(responseSchemaService, 'getResponseSchemaByPath')
|
||||
.mockResolvedValue(mockSchema as any);
|
||||
jest.spyOn(userService, 'getUserByUsername').mockResolvedValue(null);
|
||||
.mockResolvedValue({
|
||||
curStatus: {
|
||||
status: 'published',
|
||||
},
|
||||
subStatus: {
|
||||
status: '',
|
||||
},
|
||||
code: {
|
||||
baseConf: {
|
||||
passwordSwitch: true,
|
||||
password: '123456',
|
||||
},
|
||||
},
|
||||
} as ResponseSchema);
|
||||
|
||||
await expect(
|
||||
controller.whitelistValidate(surveyPath, {
|
||||
password: '123456',
|
||||
whitelist: 'nonExistentUser',
|
||||
}),
|
||||
).resolves.toEqual({ code: 200, data: null });
|
||||
});
|
||||
|
||||
it('whitelistValidate should throw WHITELIST_ERROR code when mobile or email is incorrect', async () => {
|
||||
const surveyPath = '';
|
||||
jest
|
||||
.spyOn(responseSchemaService, 'getResponseSchemaByPath')
|
||||
.mockResolvedValue({
|
||||
curStatus: {
|
||||
status: 'published',
|
||||
},
|
||||
subStatus: {
|
||||
status: '',
|
||||
},
|
||||
code: {
|
||||
baseConf: {
|
||||
passwordSwitch: true,
|
||||
password: '123456',
|
||||
whitelistType: 'CUSTOM',
|
||||
memberType: 'MOBILE',
|
||||
whitelist: ['13500000000'],
|
||||
},
|
||||
},
|
||||
} as ResponseSchema);
|
||||
await expect(
|
||||
controller.whitelistValidate(surveyPath, {
|
||||
password: '123456',
|
||||
whitelist: '13500000001',
|
||||
}),
|
||||
).rejects.toThrow(
|
||||
new HttpException('名单验证失败', EXCEPTION_CODE.WHITELIST_ERROR),
|
||||
new HttpException('验证失败', EXCEPTION_CODE.WHITELIST_ERROR),
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw HttpException when user is not a workspace member', async () => {
|
||||
const surveyPath = 'testSurveyPath';
|
||||
const mockSchema = {
|
||||
code: {
|
||||
baseConf: {
|
||||
whitelistType: 'MEMBER',
|
||||
whitelist: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
it('whitelistValidate should throw WHITELIST_ERROR code when member is incorrect', async () => {
|
||||
const surveyPath = '';
|
||||
jest
|
||||
.spyOn(responseSchemaService, 'getResponseSchemaByPath')
|
||||
.mockResolvedValue(mockSchema as any);
|
||||
jest
|
||||
.spyOn(userService, 'getUserByUsername')
|
||||
.mockResolvedValue({ _id: new Object(), username: '' } as any);
|
||||
jest
|
||||
.spyOn(workspaceMemberService, 'findAllByUserId')
|
||||
.mockResolvedValue([]);
|
||||
|
||||
.mockResolvedValue({
|
||||
curStatus: {
|
||||
status: 'published',
|
||||
},
|
||||
subStatus: {
|
||||
status: '',
|
||||
},
|
||||
code: {
|
||||
baseConf: {
|
||||
passwordSwitch: true,
|
||||
password: '123456',
|
||||
whitelistType: 'MEMBER',
|
||||
whitelist: ['Jack'],
|
||||
},
|
||||
},
|
||||
} as ResponseSchema);
|
||||
await expect(
|
||||
controller.whitelistValidate(surveyPath, {
|
||||
password: '123456',
|
||||
whitelist: 'testUser',
|
||||
whitelist: 'James',
|
||||
}),
|
||||
).rejects.toThrow(
|
||||
new HttpException('验证失败', EXCEPTION_CODE.WHITELIST_ERROR),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('whitelistValidate should return verifyId successfully', async () => {
|
||||
const surveyPath = '';
|
||||
jest
|
||||
.spyOn(responseSchemaService, 'getResponseSchemaByPath')
|
||||
.mockResolvedValue({
|
||||
curStatus: {
|
||||
status: 'published',
|
||||
},
|
||||
subStatus: {
|
||||
status: '',
|
||||
},
|
||||
code: {
|
||||
baseConf: {
|
||||
passwordSwitch: true,
|
||||
password: '123456',
|
||||
whitelistType: 'CUSTOM',
|
||||
memberType: 'MOBILE',
|
||||
whitelist: ['13500000000'],
|
||||
},
|
||||
},
|
||||
} as ResponseSchema);
|
||||
|
||||
await expect(
|
||||
controller.whitelistValidate(surveyPath, {
|
||||
password: '123456',
|
||||
whitelist: '13500000000',
|
||||
}),
|
||||
).resolves.toEqual({ code: 200, data: null });
|
||||
});
|
||||
});
|
||||
|
@ -20,7 +20,6 @@ describe('ResponseSchemaService', () => {
|
||||
findOne: jest.fn().mockResolvedValue(mockResponseSchema),
|
||||
create: jest.fn(),
|
||||
save: jest.fn(),
|
||||
updateOne: jest.fn(),
|
||||
},
|
||||
},
|
||||
],
|
||||
@ -121,24 +120,22 @@ describe('ResponseSchemaService', () => {
|
||||
describe('deleteResponseSchema', () => {
|
||||
it('should delete response schema by survey path', async () => {
|
||||
jest
|
||||
.spyOn(responseSchemaRepository, 'updateOne')
|
||||
.spyOn(responseSchemaRepository, 'findOne')
|
||||
.mockResolvedValueOnce(cloneDeep(mockResponseSchema));
|
||||
jest
|
||||
.spyOn(responseSchemaRepository, 'save')
|
||||
.mockResolvedValueOnce(undefined);
|
||||
|
||||
await service.deleteResponseSchema({
|
||||
surveyPath: mockResponseSchema.surveyPath,
|
||||
});
|
||||
|
||||
expect(responseSchemaRepository.updateOne).toHaveBeenCalledWith(
|
||||
{
|
||||
expect(responseSchemaRepository.findOne).toHaveBeenCalledWith({
|
||||
where: {
|
||||
surveyPath: mockResponseSchema.surveyPath,
|
||||
},
|
||||
{
|
||||
$set: {
|
||||
isDeleted: true,
|
||||
updatedAt: expect.any(Date),
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
expect(responseSchemaRepository.save).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -71,8 +71,8 @@ const mockClientEncryptInfo = {
|
||||
date: 1710399425273.0,
|
||||
},
|
||||
],
|
||||
createdAt: 1710399425273.0,
|
||||
updatedAt: 1710399425273.0,
|
||||
createDate: 1710399425273.0,
|
||||
updateDate: 1710399425273.0,
|
||||
};
|
||||
|
||||
describe('SurveyResponseController', () => {
|
||||
@ -178,7 +178,7 @@ describe('SurveyResponseController', () => {
|
||||
.mockResolvedValueOnce({
|
||||
_id: new ObjectId('65fc2dd77f4520858046e129'),
|
||||
clientTime: 1711025112552,
|
||||
createdAt: 1711025113146,
|
||||
createDate: 1711025113146,
|
||||
curStatus: {
|
||||
status: RECORD_STATUS.NEW,
|
||||
date: 1711025113146,
|
||||
@ -212,7 +212,7 @@ describe('SurveyResponseController', () => {
|
||||
],
|
||||
|
||||
surveyPath: 'EBzdmnSp',
|
||||
updatedAt: 1711025113146,
|
||||
updateDate: 1711025113146,
|
||||
secretKeys: [],
|
||||
} as unknown as SurveyResponse);
|
||||
jest
|
||||
|
@ -18,7 +18,6 @@ describe('SurveyResponseService', () => {
|
||||
create: jest.fn(),
|
||||
save: jest.fn(),
|
||||
count: jest.fn(),
|
||||
find: jest.fn(),
|
||||
},
|
||||
},
|
||||
],
|
||||
@ -70,12 +69,16 @@ describe('SurveyResponseService', () => {
|
||||
it('should get the total survey response count by path', async () => {
|
||||
const surveyPath = 'testPath';
|
||||
const count = 10;
|
||||
jest
|
||||
.spyOn(surveyResponseRepository, 'find')
|
||||
.mockResolvedValue(new Array(10));
|
||||
jest.spyOn(surveyResponseRepository, 'count').mockResolvedValue(count);
|
||||
|
||||
const result = await service.getSurveyResponseTotalByPath(surveyPath);
|
||||
|
||||
expect(result).toEqual(count);
|
||||
expect(surveyResponseRepository.count).toHaveBeenCalledWith({
|
||||
where: {
|
||||
surveyPath,
|
||||
'subStatus.status': { $ne: 'removed' },
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -12,7 +12,6 @@ import { UserService } from 'src/modules/auth/services/user.service';
|
||||
import { SurveyMetaService } from 'src/modules/survey/services/surveyMeta.service';
|
||||
import { Logger } from 'src/logger';
|
||||
import { User } from 'src/models/user.entity';
|
||||
import { GetWorkspaceListDto } from '../dto/getWorkspaceList.dto';
|
||||
|
||||
jest.mock('src/guards/authentication.guard');
|
||||
jest.mock('src/guards/survey.guard');
|
||||
@ -23,7 +22,6 @@ describe('WorkspaceController', () => {
|
||||
let workspaceService: WorkspaceService;
|
||||
let workspaceMemberService: WorkspaceMemberService;
|
||||
let userService: UserService;
|
||||
let logger: Logger;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
@ -33,6 +31,7 @@ describe('WorkspaceController', () => {
|
||||
provide: WorkspaceService,
|
||||
useValue: {
|
||||
create: jest.fn(),
|
||||
findAllById: jest.fn(),
|
||||
findAllByIdWithPagination: jest.fn(),
|
||||
update: jest.fn(),
|
||||
delete: jest.fn(),
|
||||
@ -48,6 +47,7 @@ describe('WorkspaceController', () => {
|
||||
batchUpdate: jest.fn(),
|
||||
batchDelete: jest.fn(),
|
||||
countByWorkspaceId: jest.fn(),
|
||||
batchSearchByWorkspace: jest.fn(),
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -80,26 +80,24 @@ describe('WorkspaceController', () => {
|
||||
WorkspaceMemberService,
|
||||
);
|
||||
userService = module.get<UserService>(UserService);
|
||||
logger = module.get<Logger>(Logger);
|
||||
});
|
||||
|
||||
describe('create', () => {
|
||||
it('should create a workspace and return workspaceId', async () => {
|
||||
const mockUserId = new ObjectId(),
|
||||
mockUsername = 'username';
|
||||
const createWorkspaceDto: CreateWorkspaceDto = {
|
||||
name: 'Test Workspace',
|
||||
description: 'Test Description',
|
||||
members: [{ userId: mockUserId.toString(), role: WORKSPACE_ROLE.USER }],
|
||||
members: [{ userId: 'userId1', role: WORKSPACE_ROLE.USER }],
|
||||
};
|
||||
const req = { user: { _id: new ObjectId(), username: 'testuser' } };
|
||||
const req = { user: { _id: new ObjectId() } };
|
||||
const createdWorkspace = { _id: new ObjectId() };
|
||||
|
||||
jest
|
||||
.spyOn(userService, 'getUserListByIds')
|
||||
.mockResolvedValue([
|
||||
{ _id: mockUserId, username: mockUsername },
|
||||
] as unknown as Array<User>);
|
||||
jest.spyOn(userService, 'getUserListByIds').mockResolvedValue([
|
||||
{
|
||||
_id: 'userId1',
|
||||
},
|
||||
] as unknown as Array<User>);
|
||||
|
||||
jest
|
||||
.spyOn(workspaceService, 'create')
|
||||
.mockResolvedValue(createdWorkspace as Workspace);
|
||||
@ -115,7 +113,6 @@ describe('WorkspaceController', () => {
|
||||
expect(workspaceService.create).toHaveBeenCalledWith({
|
||||
name: createWorkspaceDto.name,
|
||||
description: createWorkspaceDto.description,
|
||||
owner: req.user.username,
|
||||
ownerId: req.user._id.toString(),
|
||||
});
|
||||
expect(workspaceMemberService.create).toHaveBeenCalledWith({
|
||||
@ -126,31 +123,31 @@ describe('WorkspaceController', () => {
|
||||
expect(workspaceMemberService.batchCreate).toHaveBeenCalledWith({
|
||||
workspaceId: createdWorkspace._id.toString(),
|
||||
members: createWorkspaceDto.members,
|
||||
creator: req.user.username,
|
||||
creatorId: req.user._id.toString(),
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw an exception if validation fails', async () => {
|
||||
const createWorkspaceDto = { name: '', members: [] };
|
||||
const createWorkspaceDto: CreateWorkspaceDto = {
|
||||
name: '',
|
||||
members: [],
|
||||
};
|
||||
const req = { user: { _id: new ObjectId() } };
|
||||
|
||||
await expect(controller.create(createWorkspaceDto, req)).rejects.toThrow(
|
||||
HttpException,
|
||||
);
|
||||
expect(logger.error).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('findAll', () => {
|
||||
it('should return a list of workspaces for the user', async () => {
|
||||
const req = { user: { _id: new ObjectId() } };
|
||||
const queryInfo: GetWorkspaceListDto = { curPage: 1, pageSize: 10 };
|
||||
const memberList = [{ workspaceId: new ObjectId().toString() }];
|
||||
const workspaces = [{ _id: new ObjectId(), name: 'Test Workspace' }];
|
||||
|
||||
jest
|
||||
.spyOn(workspaceMemberService, 'findAllByUserId')
|
||||
.mockResolvedValue(memberList as Array<WorkspaceMember>);
|
||||
.mockResolvedValue(memberList as unknown as Array<WorkspaceMember>);
|
||||
|
||||
jest
|
||||
.spyOn(workspaceService, 'findAllByIdWithPagination')
|
||||
@ -159,11 +156,12 @@ describe('WorkspaceController', () => {
|
||||
count: workspaces.length,
|
||||
});
|
||||
|
||||
jest
|
||||
.spyOn(userService, 'getUserListByIds')
|
||||
.mockResolvedValue([{ _id: new ObjectId() }] as unknown as Array<User>);
|
||||
jest.spyOn(userService, 'getUserListByIds').mockResolvedValue([]);
|
||||
|
||||
const result = await controller.findAll(req, queryInfo);
|
||||
const result = await controller.findAll(req, {
|
||||
curPage: 1,
|
||||
pageSize: 10,
|
||||
});
|
||||
|
||||
expect(result.code).toEqual(200);
|
||||
expect(workspaceMemberService.findAllByUserId).toHaveBeenCalledWith({
|
||||
@ -176,18 +174,6 @@ describe('WorkspaceController', () => {
|
||||
name: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw an exception if validation fails', async () => {
|
||||
const req = { user: { _id: new ObjectId() } };
|
||||
const queryInfo: GetWorkspaceListDto = {
|
||||
curPage: 'not_a_number',
|
||||
pageSize: 10,
|
||||
} as any;
|
||||
|
||||
await expect(controller.findAll(req, queryInfo)).rejects.toThrow(
|
||||
HttpException,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('update', () => {
|
||||
@ -199,9 +185,11 @@ describe('WorkspaceController', () => {
|
||||
adminMembers: [],
|
||||
userMembers: [],
|
||||
};
|
||||
jest
|
||||
.spyOn(userService, 'getUserListByIds')
|
||||
.mockResolvedValue([{ _id: userId }] as Array<User>);
|
||||
jest.spyOn(userService, 'getUserListByIds').mockResolvedValue([
|
||||
{
|
||||
_id: userId,
|
||||
},
|
||||
] as Array<User>);
|
||||
const updateDto = {
|
||||
name: 'Updated Workspace',
|
||||
members: [
|
||||
@ -215,41 +203,76 @@ describe('WorkspaceController', () => {
|
||||
jest.spyOn(workspaceService, 'update').mockResolvedValue(updateResult);
|
||||
jest.spyOn(workspaceMemberService, 'batchCreate').mockResolvedValue(null);
|
||||
jest.spyOn(workspaceMemberService, 'batchUpdate').mockResolvedValue(null);
|
||||
jest.spyOn(workspaceMemberService, 'batchDelete').mockResolvedValue(null);
|
||||
|
||||
const result = await controller.update(id, updateDto, {
|
||||
user: { username: 'testuser', _id: new ObjectId() },
|
||||
const result = await controller.update(id, updateDto);
|
||||
|
||||
expect(result).toEqual({
|
||||
code: 200,
|
||||
});
|
||||
|
||||
expect(result).toEqual({ code: 200 });
|
||||
expect(workspaceService.update).toHaveBeenCalledWith({
|
||||
id,
|
||||
workspace: { name: updateDto.name },
|
||||
operator: 'testuser',
|
||||
operatorId: expect.any(String),
|
||||
expect(workspaceService.update).toHaveBeenCalledWith(id, {
|
||||
name: updateDto.name,
|
||||
});
|
||||
expect(workspaceMemberService.batchCreate).toHaveBeenCalledWith({
|
||||
workspaceId: id,
|
||||
members: members.newMembers,
|
||||
creator: 'testuser',
|
||||
creatorId: expect.any(String),
|
||||
});
|
||||
expect(workspaceMemberService.batchUpdate).toHaveBeenCalledWith({
|
||||
idList: members.adminMembers,
|
||||
role: WORKSPACE_ROLE.ADMIN,
|
||||
operator: 'testuser',
|
||||
operatorId: expect.any(String),
|
||||
});
|
||||
expect(workspaceMemberService.batchUpdate).toHaveBeenCalledWith({
|
||||
idList: members.userMembers,
|
||||
role: WORKSPACE_ROLE.USER,
|
||||
operator: 'testuser',
|
||||
operatorId: expect.any(String),
|
||||
});
|
||||
expect(workspaceMemberService.batchDelete).toHaveBeenCalledWith({
|
||||
idList: [],
|
||||
neIdList: [],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('delete', () => {
|
||||
it('should delete a workspace', async () => {
|
||||
const id = 'workspaceId';
|
||||
|
||||
jest.spyOn(workspaceService, 'delete').mockResolvedValue(null);
|
||||
|
||||
const result = await controller.delete(id);
|
||||
|
||||
expect(result).toEqual({ code: 200 });
|
||||
expect(workspaceService.delete).toHaveBeenCalledWith(id);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getWorkspaceAndMember', () => {
|
||||
it('should return a list of workspaces and members for the user', async () => {
|
||||
const userId = new ObjectId();
|
||||
jest.spyOn(userService, 'getUserListByIds').mockResolvedValue([
|
||||
{
|
||||
_id: userId,
|
||||
},
|
||||
] as Array<User>);
|
||||
const req = { user: { _id: userId } };
|
||||
const workspaceId = new ObjectId();
|
||||
const memberList = [{ workspaceId, userId }];
|
||||
const workspaces = [{ _id: workspaceId, name: 'Test Workspace' }];
|
||||
const userList = [{ _id: userId, username: 'Test User' }];
|
||||
|
||||
jest
|
||||
.spyOn(workspaceService, 'findAllByUserId')
|
||||
.mockResolvedValue(workspaces as Array<Workspace>);
|
||||
jest
|
||||
.spyOn(workspaceMemberService, 'batchSearchByWorkspace')
|
||||
.mockResolvedValue(memberList as unknown as Array<WorkspaceMember>);
|
||||
jest
|
||||
.spyOn(userService, 'getUserListByIds')
|
||||
.mockResolvedValue(userList as User[]);
|
||||
|
||||
const result = await controller.getWorkspaceAndMember(req);
|
||||
|
||||
expect(result.code).toEqual(200);
|
||||
expect(workspaceService.findAllByUserId).toHaveBeenCalledWith(
|
||||
req.user._id.toString(),
|
||||
);
|
||||
expect(
|
||||
workspaceMemberService.batchSearchByWorkspace,
|
||||
).toHaveBeenCalledWith(workspaces.map((item) => item._id.toString()));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -45,7 +45,6 @@ describe('WorkspaceService', () => {
|
||||
const workspace = {
|
||||
name: 'Test Workspace',
|
||||
description: 'Description',
|
||||
owner: 'Test Owner', // 添加 owner 属性
|
||||
ownerId: 'ownerId',
|
||||
};
|
||||
const createdWorkspace = { ...workspace, _id: new ObjectId() };
|
||||
@ -60,11 +59,7 @@ describe('WorkspaceService', () => {
|
||||
const result = await service.create(workspace);
|
||||
|
||||
expect(result).toEqual(createdWorkspace);
|
||||
expect(workspaceRepository.create).toHaveBeenCalledWith({
|
||||
...workspace,
|
||||
creator: workspace.owner,
|
||||
creatorId: workspace.ownerId,
|
||||
});
|
||||
expect(workspaceRepository.create).toHaveBeenCalledWith(workspace);
|
||||
expect(workspaceRepository.save).toHaveBeenCalledWith(createdWorkspace);
|
||||
});
|
||||
});
|
||||
@ -95,35 +90,24 @@ describe('WorkspaceService', () => {
|
||||
it('should update a workspace', async () => {
|
||||
const workspaceId = 'workspaceId';
|
||||
const updateData = { name: 'Updated Workspace' };
|
||||
const operator = 'Test Operator';
|
||||
const operatorId = 'operatorId';
|
||||
|
||||
jest
|
||||
.spyOn(workspaceRepository, 'update')
|
||||
.mockResolvedValue({ affected: 1 } as any);
|
||||
|
||||
const result = await service.update({
|
||||
id: workspaceId,
|
||||
workspace: updateData,
|
||||
operator,
|
||||
operatorId,
|
||||
});
|
||||
const result = await service.update(workspaceId, updateData);
|
||||
|
||||
expect(result).toEqual({ affected: 1 });
|
||||
expect(workspaceRepository.update).toHaveBeenCalledWith(workspaceId, {
|
||||
...updateData,
|
||||
updatedAt: expect.any(Date),
|
||||
operator,
|
||||
operatorId,
|
||||
});
|
||||
expect(workspaceRepository.update).toHaveBeenCalledWith(
|
||||
workspaceId,
|
||||
updateData,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('delete', () => {
|
||||
it('should delete a workspace and update related surveyMeta', async () => {
|
||||
const workspaceId = new ObjectId().toString();
|
||||
const operator = 'Test Operator';
|
||||
const operatorId = 'operatorId';
|
||||
|
||||
jest
|
||||
.spyOn(workspaceRepository, 'updateOne')
|
||||
@ -132,17 +116,11 @@ describe('WorkspaceService', () => {
|
||||
.spyOn(surveyMetaRepository, 'updateMany')
|
||||
.mockResolvedValue({ modifiedCount: 1 } as any);
|
||||
|
||||
const result = await service.delete(workspaceId, {
|
||||
operator,
|
||||
operatorId,
|
||||
});
|
||||
await service.delete(workspaceId);
|
||||
|
||||
expect(workspaceRepository.updateOne).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(surveyMetaRepository.updateMany).toHaveBeenCalledTimes(1);
|
||||
expect(result).toEqual({
|
||||
workspaceRes: { modifiedCount: 1 },
|
||||
surveyRes: { modifiedCount: 1 },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -161,43 +139,9 @@ describe('WorkspaceService', () => {
|
||||
.spyOn(workspaceRepository, 'find')
|
||||
.mockResolvedValue(workspaces as any);
|
||||
|
||||
const result = await service.findAllByUserId('userId');
|
||||
|
||||
const result = await service.findAllByUserId('');
|
||||
expect(result).toEqual(workspaces);
|
||||
expect(workspaceRepository.find).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('findAllByIdWithPagination', () => {
|
||||
it('should return paginated workspaces', async () => {
|
||||
const workspaceIdList = [
|
||||
new ObjectId().toString(),
|
||||
new ObjectId().toString(),
|
||||
];
|
||||
const page = 1;
|
||||
const limit = 10;
|
||||
const workspaces = [
|
||||
{ _id: workspaceIdList[0], name: 'Workspace 1' },
|
||||
{ _id: workspaceIdList[1], name: 'Workspace 2' },
|
||||
];
|
||||
|
||||
jest
|
||||
.spyOn(workspaceRepository, 'findAndCount')
|
||||
.mockResolvedValue([workspaces, workspaces.length] as any);
|
||||
|
||||
const result = await service.findAllByIdWithPagination({
|
||||
workspaceIdList,
|
||||
page,
|
||||
limit,
|
||||
});
|
||||
|
||||
expect(result).toEqual({ list: workspaces, count: workspaces.length });
|
||||
expect(workspaceRepository.findAndCount).toHaveBeenCalledWith({
|
||||
where: expect.any(Object),
|
||||
skip: 0,
|
||||
take: limit,
|
||||
order: { createdAt: -1 },
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -115,16 +115,11 @@ describe('WorkspaceMemberController', () => {
|
||||
};
|
||||
const updateResult = { modifiedCount: 1 };
|
||||
|
||||
// Mock request object
|
||||
const req = {
|
||||
user: { username: 'admin', _id: 'operatorId' },
|
||||
};
|
||||
|
||||
jest
|
||||
.spyOn(workspaceMemberService, 'updateRole')
|
||||
.mockResolvedValue(updateResult);
|
||||
|
||||
const result = await controller.updateRole(updateDto, req);
|
||||
const result = await controller.updateRole(updateDto);
|
||||
|
||||
expect(result).toEqual({
|
||||
code: 200,
|
||||
@ -133,11 +128,9 @@ describe('WorkspaceMemberController', () => {
|
||||
},
|
||||
});
|
||||
expect(workspaceMemberService.updateRole).toHaveBeenCalledWith({
|
||||
role: updateDto.role,
|
||||
workspaceId: updateDto.workspaceId,
|
||||
userId: updateDto.userId,
|
||||
operator: req.user.username,
|
||||
operatorId: req.user._id.toString(),
|
||||
role: updateDto.role,
|
||||
});
|
||||
});
|
||||
|
||||
@ -147,11 +140,8 @@ describe('WorkspaceMemberController', () => {
|
||||
userId: '',
|
||||
role: '',
|
||||
};
|
||||
const req = {
|
||||
user: { username: 'admin', _id: 'operatorId' },
|
||||
};
|
||||
|
||||
await expect(controller.updateRole(updateDto, req)).rejects.toThrow(
|
||||
await expect(controller.updateRole(updateDto)).rejects.toThrow(
|
||||
HttpException,
|
||||
);
|
||||
});
|
||||
|
@ -58,53 +58,23 @@ describe('WorkspaceMemberService', () => {
|
||||
{ userId: 'userId1', role: 'admin' },
|
||||
{ userId: 'userId2', role: 'user' },
|
||||
];
|
||||
const creator = 'creatorName';
|
||||
const creatorId = 'creatorId';
|
||||
const now = new Date();
|
||||
const dataToInsert = members.map((item) => ({
|
||||
...item,
|
||||
workspaceId,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
creator,
|
||||
creatorId,
|
||||
}));
|
||||
const dataToInsert = members.map((item) => ({ ...item, workspaceId }));
|
||||
|
||||
jest.spyOn(repository, 'insertMany').mockResolvedValueOnce({
|
||||
insertedCount: members.length,
|
||||
} as any);
|
||||
jest
|
||||
.spyOn(repository, 'insertMany')
|
||||
.mockResolvedValueOnce({ insertedCount: members.length } as any);
|
||||
|
||||
const result = await service.batchCreate({
|
||||
workspaceId,
|
||||
members,
|
||||
creator,
|
||||
creatorId,
|
||||
});
|
||||
const result = await service.batchCreate({ workspaceId, members });
|
||||
|
||||
expect(result).toEqual({ insertedCount: members.length });
|
||||
expect(repository.insertMany).toHaveBeenCalledWith(
|
||||
dataToInsert.map((item) => {
|
||||
return {
|
||||
...item,
|
||||
createdAt: expect.any(Date),
|
||||
updatedAt: expect.any(Date),
|
||||
};
|
||||
}),
|
||||
);
|
||||
expect(repository.insertMany).toHaveBeenCalledWith(dataToInsert);
|
||||
});
|
||||
|
||||
it('should return insertedCount 0 if no members to insert', async () => {
|
||||
const workspaceId = new ObjectId().toString();
|
||||
const members = [];
|
||||
const creator = 'creatorName';
|
||||
const creatorId = 'creatorId';
|
||||
|
||||
const result = await service.batchCreate({
|
||||
workspaceId,
|
||||
members,
|
||||
creator,
|
||||
creatorId,
|
||||
});
|
||||
const result = await service.batchCreate({ workspaceId, members });
|
||||
|
||||
expect(result).toEqual({ insertedCount: 0 });
|
||||
});
|
||||
@ -114,19 +84,12 @@ describe('WorkspaceMemberService', () => {
|
||||
it('should batch update workspace members roles', async () => {
|
||||
const idList = [new ObjectId().toString(), new ObjectId().toString()];
|
||||
const role = 'user';
|
||||
const operator = 'operatorName';
|
||||
const operatorId = 'operatorId';
|
||||
|
||||
jest
|
||||
.spyOn(repository, 'updateMany')
|
||||
.mockResolvedValue({ modifiedCount: idList.length } as any);
|
||||
|
||||
const result = await service.batchUpdate({
|
||||
idList,
|
||||
role,
|
||||
operator,
|
||||
operatorId,
|
||||
});
|
||||
const result = await service.batchUpdate({ idList, role });
|
||||
|
||||
expect(result).toEqual({ modifiedCount: idList.length });
|
||||
});
|
||||
@ -134,15 +97,8 @@ describe('WorkspaceMemberService', () => {
|
||||
it('should return modifiedCount 0 if no ids to update', async () => {
|
||||
const idList = [];
|
||||
const role = 'user';
|
||||
const operator = 'operatorName';
|
||||
const operatorId = 'operatorId';
|
||||
|
||||
const result = await service.batchUpdate({
|
||||
idList,
|
||||
role,
|
||||
operator,
|
||||
operatorId,
|
||||
});
|
||||
const result = await service.batchUpdate({ idList, role });
|
||||
|
||||
expect(result).toEqual({ modifiedCount: 0 });
|
||||
});
|
||||
@ -204,25 +160,17 @@ describe('WorkspaceMemberService', () => {
|
||||
const workspaceId = 'workspaceId';
|
||||
const userId = 'userId';
|
||||
const role = 'admin';
|
||||
const operator = 'operatorName';
|
||||
const operatorId = 'operatorId';
|
||||
|
||||
jest
|
||||
.spyOn(repository, 'updateOne')
|
||||
.mockResolvedValue({ modifiedCount: 1 } as any);
|
||||
|
||||
const result = await service.updateRole({
|
||||
workspaceId,
|
||||
userId,
|
||||
role,
|
||||
operator,
|
||||
operatorId,
|
||||
});
|
||||
const result = await service.updateRole({ workspaceId, userId, role });
|
||||
|
||||
expect(result).toEqual({ modifiedCount: 1 });
|
||||
expect(repository.updateOne).toHaveBeenCalledWith(
|
||||
{ workspaceId, userId },
|
||||
{ $set: { role, operator, operatorId, updatedAt: expect.any(Date) } },
|
||||
{ $set: { role } },
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { ObjectId } from 'mongodb';
|
||||
import { getPushingData } from '../messagePushing';
|
||||
import { getPushingData } from './messagePushing';
|
||||
import { RECORD_STATUS } from 'src/enums';
|
||||
|
||||
describe('getPushingData', () => {
|
@ -23,12 +23,12 @@
|
||||
"clipboard": "^2.0.11",
|
||||
"crypto-js": "^4.2.0",
|
||||
"echarts": "^5.5.0",
|
||||
"element-plus": "^2.8.5",
|
||||
"element-plus": "^2.8.3",
|
||||
"lodash-es": "^4.17.21",
|
||||
"moment": "^2.29.4",
|
||||
"nanoid": "^5.0.7",
|
||||
"node-forge": "^1.3.1",
|
||||
"pinia": "2.2.7",
|
||||
"pinia": "^2.1.7",
|
||||
"qrcode": "^1.5.3",
|
||||
"uuid": "^10.0.0",
|
||||
"vue": "^3.4.15",
|
||||
@ -57,7 +57,7 @@
|
||||
"husky": "^9.0.11",
|
||||
"npm-run-all2": "^6.1.1",
|
||||
"prettier": "^3.0.3",
|
||||
"sass": "1.79.6",
|
||||
"sass": "1.77.6",
|
||||
"typescript": "~5.3.0",
|
||||
"unplugin-auto-import": "^0.17.5",
|
||||
"unplugin-icons": "^0.18.5",
|
||||
|
@ -13,7 +13,7 @@ export const getUserInfo = () => {
|
||||
}
|
||||
/** 获取密码强度 */
|
||||
export const getPasswordStrength = (password) => {
|
||||
return axios.get('/auth/password/strength', {
|
||||
return axios.get('/auth/register/password/strength', {
|
||||
params: {
|
||||
password
|
||||
}
|
||||
|
@ -44,7 +44,7 @@
|
||||
background
|
||||
layout="prev, pager, next"
|
||||
:total="total"
|
||||
size="small"
|
||||
small
|
||||
:page-size="pageSize"
|
||||
@current-change="handleCurrentChange"
|
||||
>
|
||||
|
@ -14,6 +14,7 @@
|
||||
v-for="(content, contentIndex) in item.content"
|
||||
:key="`${item.key}${contentIndex}`"
|
||||
:form-config="content"
|
||||
v-show="isShowFormItem(content)"
|
||||
>
|
||||
<Component
|
||||
:is="components[content.type]"
|
||||
@ -82,6 +83,14 @@ const formFieldData = ref<Array<any>>([])
|
||||
const init = ref<boolean>(true)
|
||||
const components = shallowRef<any>(props.customComponents || {})
|
||||
|
||||
const isShowFormItem = (content: any) => {
|
||||
if (_isFunction(content.toggleShowFn)) {
|
||||
return content.toggleShowFn(props.moduleConfig)
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
const handleFormChange = (data: any, formConfig: any) => {
|
||||
// 处理用户操作的设置器的值
|
||||
if (_isFunction(formConfig?.valueSetter)) {
|
||||
|
@ -8,7 +8,7 @@
|
||||
{{ saveText }}
|
||||
</span>
|
||||
<i-ep-loading class="icon" v-if="autoSaveStatus === 'saving'" />
|
||||
<i-ep-check class="icon succeed" v-if="autoSaveStatus === 'succeed'" />
|
||||
<i-ep-check class="icon succeed" v-else-if="autoSaveStatus === 'succeed'" />
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
@ -99,23 +99,20 @@ const triggerAutoSave = () => {
|
||||
isShowAutoSave.value = true
|
||||
nextTick(async () => {
|
||||
try {
|
||||
const res: any = await doSave()
|
||||
if (res !== undefined) {
|
||||
if (res.code === 200) {
|
||||
autoSaveStatus.value = 'succeed'
|
||||
} else {
|
||||
autoSaveStatus.value = 'failed'
|
||||
}
|
||||
isShowAutoSave.value = true
|
||||
const res: any = await handleSave()
|
||||
if (res.code === 200) {
|
||||
autoSaveStatus.value = 'succeed'
|
||||
} else {
|
||||
autoSaveStatus.value = 'failed'
|
||||
}
|
||||
} catch (err) {
|
||||
autoSaveStatus.value = 'failed'
|
||||
isShowAutoSave.value = true
|
||||
} finally {
|
||||
|
||||
setTimeout(() => {
|
||||
isShowAutoSave.value = false
|
||||
timerHandle.value = null
|
||||
}, 300)
|
||||
} catch (err) {
|
||||
autoSaveStatus.value = 'failed'
|
||||
isShowAutoSave.value = true
|
||||
}
|
||||
})
|
||||
}, 2000)
|
||||
@ -123,17 +120,6 @@ const triggerAutoSave = () => {
|
||||
}
|
||||
|
||||
const handleSave = async () => {
|
||||
const res: any = await doSave()
|
||||
if (res !== undefined && res.code === 200) {
|
||||
ElMessage.success('保存成功')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存问卷
|
||||
* @return 无返回时说明保存失败并由函数内部完成统一提示,有返回时,code为200为保存成功,不为200时,使用errmsg由外部实现错误信息展示
|
||||
*/
|
||||
const doSave = async () => {
|
||||
if (isSaving.value) {
|
||||
return
|
||||
}
|
||||
@ -155,6 +141,7 @@ const doSave = async () => {
|
||||
return
|
||||
}
|
||||
if (res.code === 200) {
|
||||
ElMessage.success('保存成功')
|
||||
return res
|
||||
} else if (res.code === 3006) {
|
||||
ElMessageBox.alert(res.errmsg, '提示', {
|
||||
|
@ -5,7 +5,7 @@
|
||||
</div>
|
||||
<SetterField
|
||||
class="question-config-form"
|
||||
label-position="top"
|
||||
label-position="left"
|
||||
:form-config-list="formFields"
|
||||
:module-config="moduleConfig"
|
||||
@form-change="handleFormChange"
|
||||
@ -71,4 +71,25 @@ const handleFormChange = ({ key, value }: any) => {
|
||||
.question-config-form {
|
||||
padding: 30px 20px 50px 20px;
|
||||
}
|
||||
|
||||
:deep(.group-wrap) {
|
||||
margin-bottom: 0;
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.group-title {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.el-form-item {
|
||||
margin-bottom: 16px;
|
||||
|
||||
.el-radio {
|
||||
height: initial;
|
||||
line-height: initial;
|
||||
margin-bottom: initial;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -5,7 +5,9 @@
|
||||
<img src="/imgs/icons/success.webp" class="success-img" />
|
||||
<div class="title-msg" v-safe-html="successText"></div>
|
||||
</div>
|
||||
<div class="bottom-btn"></div>
|
||||
<div v-if="jumpConfig.buttonText && jumpConfig.type === 'button'" class="jump-btn">
|
||||
{{ jumpConfig.buttonText }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -17,6 +19,7 @@ interface Props {
|
||||
}
|
||||
const props = defineProps<Props>()
|
||||
const successText = computed(() => props.moduleConfig?.msgContent?.msg_200 || '')
|
||||
const jumpConfig = computed(() => props.moduleConfig?.jumpConfig || {})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
/*成功页面跳转全屏展示浮层*/
|
||||
@ -50,7 +53,18 @@ const successText = computed(() => props.moduleConfig?.msgContent?.msg_200 || ''
|
||||
font-size: 0.36rem;
|
||||
}
|
||||
}
|
||||
.bottom-btn {
|
||||
height: 300px;
|
||||
.jump-btn {
|
||||
background: var(--primary-color);
|
||||
width: 90%;
|
||||
border-radius: 0.08rem;
|
||||
padding: 0.25rem 0;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 0.25rem;
|
||||
font-weight: 500;
|
||||
margin: 0 auto;
|
||||
border: none;
|
||||
}
|
||||
</style>
|
||||
|
@ -73,7 +73,6 @@ const handleChange = (name: any) => {
|
||||
:deep(.el-tabs__content) {
|
||||
height: calc(100% - 10px);
|
||||
padding-bottom: 10px;
|
||||
overflow-y: auto;
|
||||
:deep(el-tab-pane) {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
|
@ -103,7 +103,7 @@ export default {
|
||||
type: 'WhiteList',
|
||||
custom: true, // 自定义导入高级组件
|
||||
relyFunc: (data) => {
|
||||
return data.whitelistType === 'CUSTOM'
|
||||
return data.whitelistType == 'CUSTOM'
|
||||
}
|
||||
},
|
||||
team_list: {
|
||||
@ -112,7 +112,7 @@ export default {
|
||||
type: 'TeamMemberList',
|
||||
custom: true, // 自定义导入高级组件
|
||||
relyFunc: (data) => {
|
||||
return data.whitelistType === 'MEMBER'
|
||||
return data.whitelistType == 'MEMBER'
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
export default {
|
||||
Success: [
|
||||
{
|
||||
label: '提示文案',
|
||||
title: '提示文案',
|
||||
type: 'RichText',
|
||||
key: 'msgContent.msg_200',
|
||||
placeholder: '提交成功',
|
||||
@ -9,6 +9,46 @@ export default {
|
||||
labelStyle: {
|
||||
'font-weight': 'bold'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '交卷跳转',
|
||||
type: 'Customed',
|
||||
key: 'jumpConfig',
|
||||
content: [
|
||||
{
|
||||
key: 'jumpConfig.type',
|
||||
type: 'RadioGroup',
|
||||
value: 'link',
|
||||
options: [
|
||||
{
|
||||
label: '跳转网页',
|
||||
value: 'link'
|
||||
},
|
||||
{
|
||||
label: '跳转按钮',
|
||||
value: 'button'
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'jumpConfig.buttonText',
|
||||
label: '按钮文案',
|
||||
type: 'InputSetter',
|
||||
placeholder: '请输入按钮文案',
|
||||
value: '',
|
||||
toggleShowFn: (data) => {
|
||||
return data?.jumpConfig?.type === 'button'
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'jumpConfig.link',
|
||||
label: '跳转链接',
|
||||
type: 'InputSetter',
|
||||
placeholder: '请输入网址',
|
||||
value: '',
|
||||
},
|
||||
|
||||
]
|
||||
}
|
||||
],
|
||||
OverTime: [
|
||||
|
@ -17,9 +17,7 @@ export default function usePageEdit(
|
||||
updateTime: () => void
|
||||
) {
|
||||
const pageConf = computed(() => schema.pageConf)
|
||||
const pageEditOne = computed(() => {
|
||||
return schema.pageEditOne
|
||||
})
|
||||
const pageEditOne = computed(() => schema.pageEditOne)
|
||||
const isFinallyPage = computed(() => {
|
||||
return pageEditOne.value === pageConf.value.length
|
||||
})
|
||||
|
@ -64,6 +64,7 @@ export default defineComponent({
|
||||
const onRadioClick = (item, $event) => {
|
||||
$event && $event.stopPropagation()
|
||||
$event && $event.preventDefault()
|
||||
|
||||
if (!isChecked(item)) {
|
||||
emit('change', item.hash)
|
||||
}
|
||||
|
@ -91,8 +91,10 @@ const questionConfig = computed(() => {
|
||||
const updateFormData = (value) => {
|
||||
const key = props.moduleConfig.field
|
||||
const formData = cloneDeep(formValues.value)
|
||||
formData[key] = value
|
||||
console.log(formData)
|
||||
if (key in formData) {
|
||||
formData[key] = value
|
||||
}
|
||||
|
||||
return formData
|
||||
}
|
||||
|
||||
|
@ -1,147 +0,0 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="whiteVisible"
|
||||
title="验证"
|
||||
:show-close="false"
|
||||
class="verify-white-wrap"
|
||||
width="315"
|
||||
:close-on-press-escape="false"
|
||||
:close-on-click-modal="false"
|
||||
align-center
|
||||
>
|
||||
<template #header>
|
||||
<div class="verify-white-head">
|
||||
<div class="verify-white-title">验证</div>
|
||||
<div v-if="whitelistTip" class="verify-white-tips">{{ whitelistTip }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="verify-white-body">
|
||||
<el-input
|
||||
v-if="isPwd"
|
||||
v-model="state.password"
|
||||
class="wd255 mb16"
|
||||
placeholder="请输入6位字符串类型访问密码"
|
||||
/>
|
||||
<el-input
|
||||
v-if="isValue"
|
||||
v-model="state.value"
|
||||
class="wd255 mb16"
|
||||
:placeholder="placeholder"
|
||||
/>
|
||||
<div class="submit-btn" @click="handleSubmit">验证并开始答题</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, reactive, computed, watch } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import 'element-plus/theme-chalk/src/message.scss'
|
||||
|
||||
import { validate } from '../api/survey'
|
||||
import { useSurveyStore } from '../stores/survey'
|
||||
|
||||
const whiteVisible = ref(false)
|
||||
|
||||
const surveyStore = useSurveyStore()
|
||||
const state = reactive({
|
||||
password: '',
|
||||
value: '',
|
||||
is_submit: false
|
||||
})
|
||||
|
||||
const baseConf = computed(() => store.state.baseConf || {})
|
||||
const isPwd = computed(() => baseConf.value.passwordSwitch)
|
||||
const whitelistType = computed(() => baseConf.value.whitelistType)
|
||||
const memberType = computed(() => baseConf.value.memberType)
|
||||
const whitelistTip = computed(() => baseConf.value.whitelistTip)
|
||||
const surveyPath = computed(() => store.state?.surveyPath || '')
|
||||
|
||||
const isValue = computed(() => {
|
||||
if (!whitelistType.value) return false
|
||||
return whitelistType.value != 'ALL'
|
||||
})
|
||||
|
||||
const placeholder = computed(() => {
|
||||
if (whitelistType.value == 'MEMBER') {
|
||||
return '请输入用户名'
|
||||
}
|
||||
if (memberType.value == 'MOBILE') {
|
||||
return '请输入手机号'
|
||||
}
|
||||
if (memberType.value == 'EMAIL') {
|
||||
return '请输入邮箱'
|
||||
}
|
||||
return ''
|
||||
})
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (state.is_submit) return
|
||||
const params = {
|
||||
surveyPath: surveyPath.value
|
||||
}
|
||||
if (isValue.value) {
|
||||
params.whitelist = state.value
|
||||
}
|
||||
if (isPwd.value) {
|
||||
params.password = state.password
|
||||
}
|
||||
const res = await validate(params)
|
||||
if (res.code != 200) {
|
||||
ElMessage.error(res.errmsg || '验证失败')
|
||||
return
|
||||
}
|
||||
whiteVisible.value = false
|
||||
surveyStore.setWhiteData(params)
|
||||
}
|
||||
|
||||
watch(
|
||||
() => baseConf.value,
|
||||
() => {
|
||||
if (whiteVisible.value) return
|
||||
if (isValue.value || isPwd.value) {
|
||||
whiteVisible.value = true
|
||||
}
|
||||
}
|
||||
)
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.verify-white-wrap {
|
||||
.verify-white-body {
|
||||
padding: 0 14px;
|
||||
}
|
||||
.verify-white-head {
|
||||
padding: 0 14px;
|
||||
margin-bottom: 8px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
.mb16 {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.verify-white-tips {
|
||||
text-align: center;
|
||||
margin-top: 8px;
|
||||
font-size: 14px;
|
||||
color: #92949d;
|
||||
}
|
||||
.verify-white-title {
|
||||
font-size: 16px;
|
||||
color: #292a36;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.submit-btn {
|
||||
background: #faa600;
|
||||
border-radius: 2px;
|
||||
width: 255px;
|
||||
height: 32px;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -16,13 +16,17 @@
|
||||
>
|
||||
重新填写
|
||||
</router-link>
|
||||
|
||||
<a v-if="showJumpButton" :href="jumpConfig.link" class="jump-btn">
|
||||
{{ jumpConfig.buttonText }}
|
||||
</a>
|
||||
</div>
|
||||
<LogoIcon :logo-conf="logoConf" :readonly="true" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { computed, ref, watchEffect } from 'vue'
|
||||
import { useSurveyStore } from '../stores/survey'
|
||||
// @ts-ignore
|
||||
import communalLoader from '@materials/communals/communalLoader.js'
|
||||
@ -37,6 +41,20 @@ const successMsg = computed(() => {
|
||||
const msgContent = (surveyStore?.submitConf as any)?.msgContent || {}
|
||||
return msgContent?.msg_200 || '提交成功'
|
||||
})
|
||||
|
||||
const jumpConfig = computed(() => {
|
||||
return (surveyStore?.submitConf as any)?.jumpConfig || {}
|
||||
})
|
||||
|
||||
const showJumpButton = ref(false)
|
||||
|
||||
watchEffect(() => {
|
||||
const { jumpConfig } = (surveyStore?.submitConf || {}) as any
|
||||
if (jumpConfig?.type === 'link' && jumpConfig?.link) {
|
||||
window.location.href = jumpConfig.link
|
||||
}
|
||||
showJumpButton.value = jumpConfig?.type === 'button' && jumpConfig?.buttonText
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import '@/render/styles/variable.scss';
|
||||
@ -87,5 +105,20 @@ const successMsg = computed(() => {
|
||||
text-decoration: underline;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.jump-btn {
|
||||
background: var(--primary-color);
|
||||
width: 90%;
|
||||
border-radius: 0.08rem;
|
||||
padding: 0.2rem 0;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 0.3rem;
|
||||
font-weight: 500;
|
||||
margin: 0.5rem auto 0;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -103,7 +103,7 @@ export const useQuestionStore = defineStore('question', () => {
|
||||
const pageIndex = ref(1) // 当前分页的索引
|
||||
const changeField = ref(null)
|
||||
const changeIndex = computed(() => {
|
||||
return questionData.value[changeField.value]?.index
|
||||
return questionData.value[changeField.value].index
|
||||
})
|
||||
const needHideFields = ref([])
|
||||
|
||||
|
@ -161,7 +161,9 @@ export const useSurveyStore = defineStore('survey', () => {
|
||||
// 用户输入或者选择后,更新表单数据
|
||||
const changeData = (data) => {
|
||||
let { key, value } = data
|
||||
formValues.value[key] = value
|
||||
if (key in formValues.value) {
|
||||
formValues.value[key] = value
|
||||
}
|
||||
questionStore.setChangeField(key)
|
||||
}
|
||||
|
||||
|
@ -114,7 +114,6 @@ export default defineConfig({
|
||||
css: {
|
||||
preprocessorOptions: {
|
||||
scss: {
|
||||
api: 'modern-compiler',
|
||||
additionalData: `@use "@/management/styles/element-variables.scss" as *;`
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user