|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace Tests\Feature;
|
|
|
|
|
|
|
|
|
|
use App\Http\Controllers\Admin\CourseContentEvaluationAskController;
|
|
|
|
|
use App\Http\Controllers\Admin\CourseContentEvaluationsController;
|
|
|
|
|
use App\Models\Admin;
|
|
|
|
|
use App\Models\User;
|
|
|
|
|
use Illuminate\Database\Schema\Blueprint;
|
|
|
|
|
use Illuminate\Support\Facades\Auth;
|
|
|
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
|
use Illuminate\Support\Facades\Schema;
|
|
|
|
|
use Tests\TestCase;
|
|
|
|
|
|
|
|
|
|
class SurveyWorkflowTest extends TestCase
|
|
|
|
|
{
|
|
|
|
|
protected function setUp(): void
|
|
|
|
|
{
|
|
|
|
|
parent::setUp();
|
|
|
|
|
config(['database.default' => 'sqlite', 'database.connections.sqlite.database' => ':memory:', 'audit.enabled' => false]);
|
|
|
|
|
DB::purge('sqlite');
|
|
|
|
|
$this->withoutMiddleware();
|
|
|
|
|
foreach (['2025_06_30_105931_create_course_content_evaluation_asks_table.php', '2025_06_30_105932_create_course_content_evaluation_forms_table.php', '2025_07_03_093224_create_course_content_evaluations_table.php', '2026_01_13_094952_add_dimensions_to_course_content_evaluation_asks_table.php', '2026_10_09_000001_extend_survey_questions_and_snapshots.php', '2026_10_12_000001_add_survey_audience.php'] as $migration) {
|
|
|
|
|
(require database_path('migrations/' . $migration))->up();
|
|
|
|
|
}
|
|
|
|
|
foreach (['users', 'course_contents', 'teachers'] as $name) {
|
|
|
|
|
Schema::create($name, function (Blueprint $table) { $table->id(); $table->softDeletes(); });
|
|
|
|
|
}
|
|
|
|
|
$user = new User();
|
|
|
|
|
$user->forceFill(['id' => 200, 'mobile' => '13800000000']);
|
|
|
|
|
Auth::guard('mobile')->setUser($user);
|
|
|
|
|
$admin = new Admin();
|
|
|
|
|
$admin->forceFill(['id' => 1, 'department_id' => 1]);
|
|
|
|
|
Auth::guard('admin')->setUser($admin);
|
|
|
|
|
// The existing audit logger queries MySQL column comments; keep this integration test SQLite-only.
|
|
|
|
|
$this->app->bind(CourseContentEvaluationAskController::class, fn () => new class extends CourseContentEvaluationAskController {
|
|
|
|
|
protected function saveLogs($original, $model) {}
|
|
|
|
|
});
|
|
|
|
|
$this->app->bind(CourseContentEvaluationsController::class, fn () => new class extends CourseContentEvaluationsController {
|
|
|
|
|
protected function saveLogs($original, $model) {}
|
|
|
|
|
});
|
|
|
|
|
DB::table('course_content_evaluations')->insert(['id' => 10, 'title' => '培训问卷', 'status' => 1]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function tearDown(): void
|
|
|
|
|
{
|
|
|
|
|
Auth::guard('mobile')->forgetUser();
|
|
|
|
|
Auth::guard('admin')->forgetUser();
|
|
|
|
|
DB::disconnect('sqlite');
|
|
|
|
|
parent::tearDown();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function createQuestion(): int
|
|
|
|
|
{
|
|
|
|
|
$response = $this->postJson('/api/admin/course-content-evaluation-ask/save', [
|
|
|
|
|
'course_content_evaluation_id' => 10, 'name' => '融资对接', 'field' => 'finance', 'edit_input' => 'multi_dimension', 'sort' => 2,
|
|
|
|
|
'dimensions' => [
|
|
|
|
|
['field' => 'count', 'name' => '意向数量', 'edit_input' => 'number', 'need_fill' => true, 'config' => ['integer' => true, 'min' => 0]],
|
|
|
|
|
['field' => 'follow', 'name' => '需要跟进', 'edit_input' => 'radio', 'need_fill' => true, 'select_item' => [['key' => 'yes', 'value' => '是'], ['key' => 'no', 'value' => '否']]],
|
|
|
|
|
],
|
|
|
|
|
])->assertOk()->assertJsonPath('name', '融资对接');
|
|
|
|
|
return $response->json('id');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testFileAnswersValidateOwnershipAndReturnNames(): void
|
|
|
|
|
{
|
|
|
|
|
Schema::create('uploads', function (Blueprint $table) { $table->id(); $table->string('original_name'); $table->string('folder'); $table->string('name'); $table->string('extension'); $table->integer('size'); $table->integer('creator_id'); $table->timestamp('created_at')->nullable(); });
|
|
|
|
|
\Illuminate\Support\Facades\Storage::fake('public');
|
|
|
|
|
$upload = $this->post('/api/mobile/upload-file', ['file' => \Illuminate\Http\UploadedFile::fake()->create('tmp.pdf', 10, 'application/pdf'), 'original_name' => '原始材料.pdf'])->assertOk()->assertJsonPath('original_name', '原始材料.pdf')->assertJsonPath('creator_id', 200);
|
|
|
|
|
\Illuminate\Support\Facades\Storage::disk('public')->assertExists('files/'.$upload->json('name'));
|
|
|
|
|
$this->post('/api/mobile/upload-file', [])->assertJsonPath('errmsg', '请选择有效文件');
|
|
|
|
|
DB::table('uploads')->insert([
|
|
|
|
|
['id' => 81, 'original_name' => '调研附件.pdf', 'folder' => 'storage/files', 'name' => '81.pdf', 'extension' => 'pdf', 'size' => 100, 'creator_id' => 200],
|
|
|
|
|
['id' => 82, 'original_name' => '他人附件.pdf', 'folder' => 'storage/files', 'name' => '82.pdf', 'extension' => 'pdf', 'size' => 100, 'creator_id' => 201],
|
|
|
|
|
]);
|
|
|
|
|
$question = ['course_content_evaluation_id' => 10, 'name' => '上传附件', 'field' => 'attachment', 'edit_input' => 'file', 'need_fill' => true, 'config' => ['max_files' => 1, 'allowed_extensions' => ['pdf']]];
|
|
|
|
|
$id = $this->postJson('/api/admin/course-content-evaluation-ask/save', $question)->assertJsonPath('edit_input', 'file')->json('id');
|
|
|
|
|
$this->post('/api/mobile/upload-file', ['file' => \Illuminate\Http\UploadedFile::fake()->create('blocked.docx', 10), 'survey_question_id' => $id])->assertJsonPath('errmsg', '只允许上传 pdf 格式');
|
|
|
|
|
$this->assertSame(3, DB::table('uploads')->count());
|
|
|
|
|
$allowedUpload = $this->post('/api/mobile/upload-file', ['file' => \Illuminate\Http\UploadedFile::fake()->create('ALLOWED.PDF', 10), 'survey_question_id' => $id])->assertJsonPath('extension', 'pdf');
|
|
|
|
|
DB::table('uploads')->insert(['id' => 90, 'original_name' => '文件.docx', 'folder' => 'storage/files', 'name' => '90.docx', 'extension' => 'docx', 'size' => 100, 'creator_id' => 200]);
|
|
|
|
|
$payload = ['course_content_evaluation_id' => 10, 'answer_version' => 2, 'data' => [['id' => $id, 'value' => []]]];
|
|
|
|
|
$url = '/api/mobile/course/course-content-form';
|
|
|
|
|
$this->postJson($url, $payload)->assertJsonPath('errmsg', '上传附件:请填写此项');
|
|
|
|
|
foreach ([[['id' => 90]], [['id' => 82]], [['id' => 999]], [['id' => 81], ['id' => 82]]] as $invalid) {
|
|
|
|
|
$payload['data'][0]['value'] = $invalid;
|
|
|
|
|
$this->assertNotEmpty($this->postJson($url, $payload)->json('errmsg'));
|
|
|
|
|
$this->assertSame(0, DB::table('course_content_evaluation_forms')->count());
|
|
|
|
|
}
|
|
|
|
|
$payload['data'][0]['value'] = [['id' => 81, 'original_name' => 'fake', 'url' => 'https://evil.invalid']];
|
|
|
|
|
$replyId = $this->postJson($url, $payload)->assertJsonPath('data.0.value.0.original_name', '调研附件.pdf')->json('id');
|
|
|
|
|
$this->getJson('/api/admin/course-content-evaluation-form/show?id='.$replyId)->assertJsonPath('questions.0.display_value', '调研附件.pdf')->assertJsonPath('questions.0.value.0.id', 81);
|
|
|
|
|
$download = '/api/admin/course-content-evaluation-form/show?id='.$replyId.'&download_file_id=';
|
|
|
|
|
$this->get($download.'81')->assertStatus(404)->assertJsonPath('errmsg', '服务器上的附件文件不存在,请检查文件是否已同步');
|
|
|
|
|
\Illuminate\Support\Facades\Storage::disk('public')->put('files/81.pdf', 'example attachment');
|
|
|
|
|
$this->get($download.'81')->assertOk()->assertStreamedContent('example attachment');
|
|
|
|
|
$this->get($download.'82')->assertStatus(403);
|
|
|
|
|
|
|
|
|
|
$this->getJson('/api/admin/course-content-evaluation-form/text-answers?course_content_evaluation_id=10&question_id='.$id)->assertJsonPath('data.0.files.0.original_name', '调研附件.pdf');
|
|
|
|
|
$this->getJson('/api/mobile/course/evaluation-detail?course_content_evaluation_id=10')->assertJsonPath('my_response.questions.0.value.0.id', 81);
|
|
|
|
|
$this->postJson($url, $payload)->assertJsonPath('id', $replyId);
|
|
|
|
|
$this->assertSame(1, DB::table('course_content_evaluation_forms')->count());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testAudienceAndDeadlineProtectEntryAndSubmission(): void
|
|
|
|
|
{
|
|
|
|
|
Schema::create('courses', function (Blueprint $table) { $table->id(); $table->softDeletes(); });
|
|
|
|
|
Schema::create('course_signs', function (Blueprint $table) { $table->id(); $table->integer('user_id'); $table->integer('course_id'); $table->integer('status'); $table->softDeletes(); });
|
|
|
|
|
DB::table('courses')->insert([['id' => 11], ['id' => 12]]);
|
|
|
|
|
$id = $this->createQuestion();
|
|
|
|
|
$detail = '/api/mobile/course/evaluation-detail?course_content_evaluation_id=10';
|
|
|
|
|
$submit = '/api/mobile/course/course-content-form';
|
|
|
|
|
$payload = ['course_content_evaluation_id' => 10, 'answer_version' => 2, 'data' => [['id' => $id, 'value' => ['count' => 0, 'follow' => 'no']]]];
|
|
|
|
|
$this->getJson($detail)->assertJsonMissing(['access_error' => '您还未报名相关课程']);
|
|
|
|
|
$this->postJson('/api/admin/course-content-evaluations/save', ['id' => 10, 'audience_course_ids' => [11, 12]])->assertJsonPath('audience_course_ids', [11, 12]);
|
|
|
|
|
foreach ([null, 0, 2, 4] as $status) {
|
|
|
|
|
DB::table('course_signs')->delete();
|
|
|
|
|
if ($status !== null) DB::table('course_signs')->insert(['user_id' => 200, 'course_id' => 12, 'status' => $status]);
|
|
|
|
|
$this->getJson($detail)->assertJsonPath('access_error', '您还未报名相关课程')->assertJsonMissing(['schema_hash']);
|
|
|
|
|
$this->postJson($submit, $payload)->assertJsonPath('access_error', '您还未报名相关课程');
|
|
|
|
|
$this->assertSame(0, DB::table('course_content_evaluation_forms')->count());
|
|
|
|
|
}
|
|
|
|
|
DB::table('course_signs')->update(['status' => 1]);
|
|
|
|
|
$this->assertNotEmpty($this->getJson($detail)->json('schema_hash'));
|
|
|
|
|
$replyId = $this->postJson($submit, $payload)->assertOk()->json('id');
|
|
|
|
|
$this->assertNotNull($replyId);
|
|
|
|
|
DB::table('course_content_evaluations')->where('id', 10)->update(['end_time' => '2000-01-01 00:00:00']);
|
|
|
|
|
$this->getJson($detail)->assertJsonPath('access_error', '当前问卷已截止');
|
|
|
|
|
$this->postJson($submit, $payload)->assertJsonPath('access_error', '当前问卷已截止');
|
|
|
|
|
$this->assertSame(1, DB::table('course_content_evaluation_forms')->count());
|
|
|
|
|
DB::table('course_content_evaluations')->where('id', 10)->update(['end_time' => null]);
|
|
|
|
|
$this->postJson('/api/admin/course-content-evaluations/save', ['id' => 10, 'audience_course_ids' => []])->assertJsonPath('audience_course_ids', []);
|
|
|
|
|
DB::table('course_signs')->delete();
|
|
|
|
|
$this->assertNotEmpty($this->getJson($detail)->json('schema_hash'));
|
|
|
|
|
$this->postJson('/api/admin/course-content-evaluations/save', ['id' => 10, 'audience_course_ids' => [999]])->assertJsonPath('errmsg', '限定人群中存在无效课程');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testConditionsRejectBreakingEditsAndRollBack(): void
|
|
|
|
|
{
|
|
|
|
|
$base = '/api/admin/course-content-evaluation-ask/';
|
|
|
|
|
$parent = ['course_content_evaluation_id' => 10, 'name' => '保险', 'field' => 'insurance', 'edit_input' => 'radio', 'sort' => 1, 'select_item' => [['key' => 'yes', 'value' => '需要'], ['key' => 'no', 'value' => '不需要']]];
|
|
|
|
|
$parent['id'] = $this->postJson($base.'save', $parent)->assertOk()->json('id');
|
|
|
|
|
$child = ['course_content_evaluation_id' => 10, 'name' => '身份证', 'field' => 'idcard', 'edit_input' => 'text', 'sort' => 2, 'config' => ['visible_when' => ['field' => 'insurance', 'value' => 'yes']]];
|
|
|
|
|
$id = $this->postJson($base.'save', $child)->assertOk()->assertJsonPath('config.visible_when.value', 'yes')->json('id');
|
|
|
|
|
$parent['select_item'] = [['key' => 'no', 'value' => '不需要']];
|
|
|
|
|
$this->postJson($base.'save', $parent)->assertJsonPath('errmsg', '身份证:显示条件引用的选项不存在,请先调整条件');
|
|
|
|
|
$this->assertStringContainsString('yes', DB::table('course_content_evaluation_asks')->where('id', $parent['id'])->value('select_item'));
|
|
|
|
|
$this->getJson($base.'destroy?id='.$parent['id'])->assertJsonPath('errmsg', '身份证:显示条件只能引用本题之前的单选或多选题,请先调整条件');
|
|
|
|
|
$this->assertNull(DB::table('course_content_evaluation_asks')->where('id', $parent['id'])->value('deleted_at'));
|
|
|
|
|
$this->postJson($base.'reorder', ['course_content_evaluation_id' => 10, 'ids' => [$id, $parent['id']]])->assertJsonPath('errmsg', '身份证:显示条件只能引用本题之前的单选或多选题,请先调整条件');
|
|
|
|
|
$this->assertSame(1, (int) DB::table('course_content_evaluation_asks')->where('id', $parent['id'])->value('sort'));
|
|
|
|
|
$child['id'] = $id;
|
|
|
|
|
$child['config'] = [];
|
|
|
|
|
$this->postJson($base.'save', $child)->assertOk()->assertJsonPath('id', $id);
|
|
|
|
|
$this->getJson($base.'destroy?id='.$parent['id'])->assertOk();
|
|
|
|
|
$this->assertNotNull(DB::table('course_content_evaluation_asks')->where('id', $parent['id'])->value('deleted_at'));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testFullSubmissionStatisticsSnapshotAndStructureLock(): void
|
|
|
|
|
{
|
|
|
|
|
$id = $this->createQuestion();
|
|
|
|
|
$definition = $this->getJson('/api/mobile/course/evaluation-detail?course_content_evaluation_id=10')->assertOk();
|
|
|
|
|
$hash = $definition->json('schema_hash');
|
|
|
|
|
$this->assertNotEmpty($hash);
|
|
|
|
|
$payload = ['course_content_evaluation_id' => 10, 'answer_version' => 2, 'schema_hash' => $hash, 'data' => [['id' => $id, 'name' => '伪造标题', 'value' => ['count' => 0, 'follow' => 'no']]]];
|
|
|
|
|
$reply = $this->postJson('/api/mobile/course/course-content-form', $payload)->assertOk()
|
|
|
|
|
->assertJsonPath('user_id', 200)->assertJsonPath('snapshot.version', 2)
|
|
|
|
|
->assertJsonPath('snapshot.questions.0.name', '融资对接');
|
|
|
|
|
$replyId = $reply->json('id');
|
|
|
|
|
$this->assertSame(1, DB::table('course_content_evaluation_forms')->count());
|
|
|
|
|
$this->postJson('/api/mobile/course/course-content-form', $payload)->assertJsonPath('id', $replyId);
|
|
|
|
|
$this->assertSame(1, DB::table('course_content_evaluation_forms')->count());
|
|
|
|
|
$this->getJson('/api/admin/course-content-evaluation-form/statistics?course_content_evaluation_id=10')
|
|
|
|
|
->assertJsonPath('responses', 1)->assertJsonPath('questions.0.dimensions.0.stats.valid_count', 1)
|
|
|
|
|
->assertJsonPath('questions.0.dimensions.0.stats.sum', 0)->assertJsonPath('questions.0.dimensions.1.stats.options.1.count', 1);
|
|
|
|
|
$this->getJson('/api/admin/course-content-evaluation-form/show?id=' . $replyId)
|
|
|
|
|
->assertJsonPath('questions.0.dimensions.0.display_value', '0')
|
|
|
|
|
->assertJsonPath('questions.0.dimensions.1.display_value', '否');
|
|
|
|
|
$this->postJson('/api/admin/course-content-evaluation-ask/save', ['id' => $id, 'name' => '改名'])->assertJsonPath('errmsg', '已有答卷,不能修改题目结构;请新建问卷');
|
|
|
|
|
$this->getJson('/api/admin/course-content-evaluation-ask/destroy?id=' . $id)->assertJsonPath('errmsg', '已有答卷,不能删除题目');
|
|
|
|
|
$this->postJson('/api/admin/course-content-evaluation-ask/reorder', ['course_content_evaluation_id' => 10, 'ids' => [$id]])->assertJsonPath('errmsg', '已有答卷,不能调整题目顺序');
|
|
|
|
|
$this->postJson('/api/admin/course-content-evaluations/save', ['id' => 10, 'title' => '改标题'])->assertJsonPath('errmsg', '已有答卷,仅可调整开放时间与发布状态;请新建问卷修改内容');
|
|
|
|
|
$this->postJson('/api/admin/course-content-evaluations/save', ['id' => 10, 'status' => 0])->assertJsonPath('status', 0);
|
|
|
|
|
// Even an out-of-band definition change cannot rewrite an existing reply.
|
|
|
|
|
DB::table('course_content_evaluation_asks')->where('id', $id)->update(['name' => '数据库修改']);
|
|
|
|
|
$this->getJson('/api/admin/course-content-evaluation-form/show?id=' . $replyId)->assertJsonPath('questions.0.name', '融资对接');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testMobileReentryReturnsOnlyOwnSnapshot(): void
|
|
|
|
|
{
|
|
|
|
|
$id = $this->createQuestion();
|
|
|
|
|
$url = '/api/mobile/course/evaluation-detail?course_content_evaluation_id=10';
|
|
|
|
|
$this->getJson($url)->assertJsonPath('my_response', null);
|
|
|
|
|
$this->postJson('/api/mobile/course/course-content-form', [
|
|
|
|
|
'course_content_evaluation_id' => 10, 'answer_version' => 2,
|
|
|
|
|
'data' => [['id' => $id, 'value' => ['count' => 0, 'follow' => 'no']]],
|
|
|
|
|
])->assertOk();
|
|
|
|
|
DB::table('course_content_evaluations')->where('id', 10)->update(['title' => '新标题', 'status' => 0]);
|
|
|
|
|
DB::table('course_content_evaluation_asks')->where('id', $id)->update(['name' => '新题目']);
|
|
|
|
|
$this->getJson($url)->assertJsonPath('my_response.title', '培训问卷')
|
|
|
|
|
->assertJsonPath('my_response.questions.0.name', '融资对接')
|
|
|
|
|
->assertJsonPath('my_response.questions.0.value.count', 0)
|
|
|
|
|
->assertJsonPath('my_response.questions.0.dimensions.1.selected_keys.0', 'no');
|
|
|
|
|
$other = new User();
|
|
|
|
|
$other->forceFill(['id' => 201]);
|
|
|
|
|
Auth::guard('mobile')->setUser($other);
|
|
|
|
|
$this->getJson($url)->assertJsonPath('my_response', null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testResubmissionUpdatesSameReplyAndRequiresBoundProfile(): void
|
|
|
|
|
{
|
|
|
|
|
$id = $this->createQuestion();
|
|
|
|
|
$payload = ['course_content_evaluation_id' => 10, 'answer_version' => 2, 'data' => [['id' => $id, 'value' => ['count' => 0, 'follow' => 'no']]]];
|
|
|
|
|
$replyId = $this->postJson('/api/mobile/course/course-content-form', $payload)->assertOk()->json('id');
|
|
|
|
|
$payload['data'][0]['value'] = ['count' => 8, 'follow' => 'yes'];
|
|
|
|
|
$this->postJson('/api/mobile/course/course-content-form', $payload)->assertJsonPath('id', $replyId)->assertJsonPath('data.0.value.count', 8);
|
|
|
|
|
$this->assertSame(1, DB::table('course_content_evaluation_forms')->count());
|
|
|
|
|
$this->getJson('/api/admin/course-content-evaluation-form/statistics?course_content_evaluation_id=10')->assertJsonPath('responses', 1)->assertJsonPath('questions.0.dimensions.0.stats.sum', 8);
|
|
|
|
|
$payload['data'][0]['value']['count'] = -1;
|
|
|
|
|
$this->postJson('/api/mobile/course/course-content-form', $payload)->assertJsonPath('errcode', 10001);
|
|
|
|
|
$this->getJson('/api/mobile/course/evaluation-detail?course_content_evaluation_id=10')->assertJsonPath('my_response.questions.0.value.count', 8);
|
|
|
|
|
DB::table('course_content_evaluations')->where('id', 10)->update(['end_time' => '2020-01-01 00:00:00']);
|
|
|
|
|
$this->postJson('/api/mobile/course/course-content-form', $payload)->assertJsonPath('access_error', '当前问卷已截止');
|
|
|
|
|
DB::table('course_content_evaluations')->where('id', 10)->update(['end_time' => null]);
|
|
|
|
|
$guest = new User();
|
|
|
|
|
$guest->forceFill(['id' => 201]);
|
|
|
|
|
Auth::guard('mobile')->setUser($guest);
|
|
|
|
|
$this->getJson('/api/mobile/course/evaluation-detail?course_content_evaluation_id=10')->assertJsonPath('requires_profile', true)->assertJsonPath('my_response', null);
|
|
|
|
|
$this->postJson('/api/mobile/course/course-content-form', $payload)->assertJsonPath('errmsg', '请先绑定或注册');
|
|
|
|
|
$this->assertSame(1, DB::table('course_content_evaluation_forms')->count());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testProfileFieldConfigurationIsValidatedAndStored(): void
|
|
|
|
|
{
|
|
|
|
|
$payload = ['course_content_evaluation_id' => 10, 'name' => '姓名', 'field' => 'student_name', 'edit_input' => 'text', 'config' => ['user_field' => 'name']];
|
|
|
|
|
$this->postJson('/api/admin/course-content-evaluation-ask/save', $payload)->assertJsonPath('config.user_field', 'name');
|
|
|
|
|
$payload['field'] = 'invalid_field';
|
|
|
|
|
$payload['config']['user_field'] = 'password';
|
|
|
|
|
$this->postJson('/api/admin/course-content-evaluation-ask/save', $payload)->assertJsonPath('errcode', 10001);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testInvalidQuantityAndStaleSchemaDoNotCreateReplies(): void
|
|
|
|
|
{
|
|
|
|
|
$id = $this->createQuestion();
|
|
|
|
|
$payload = ['course_content_evaluation_id' => 10, 'answer_version' => 2, 'data' => [['id' => $id, 'value' => ['count' => -1, 'follow' => 'no']]]];
|
|
|
|
|
$this->postJson('/api/mobile/course/course-content-form', $payload)->assertJsonPath('errcode', 10001);
|
|
|
|
|
$payload['schema_hash'] = 'stale';
|
|
|
|
|
$this->postJson('/api/mobile/course/course-content-form', $payload)->assertJsonPath('errmsg', '问卷已更新,请刷新后重新填写');
|
|
|
|
|
$this->assertSame(0, DB::table('course_content_evaluation_forms')->count());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testAtomicReorderRequiresCompleteList(): void
|
|
|
|
|
{
|
|
|
|
|
$id = $this->createQuestion();
|
|
|
|
|
$chapter = $this->postJson('/api/admin/course-content-evaluation-ask/save', ['course_content_evaluation_id' => 10, 'name' => '第五部分', 'field' => 'section', 'edit_input' => 'section', 'sort' => 1])->assertOk()->json('id');
|
|
|
|
|
$this->postJson('/api/admin/course-content-evaluation-ask/reorder', ['course_content_evaluation_id' => 10, 'ids' => [$id, $id]])->assertJsonPath('errmsg', '题目列表已变更,请刷新');
|
|
|
|
|
$this->postJson('/api/admin/course-content-evaluation-ask/reorder', ['course_content_evaluation_id' => 10, 'ids' => [$chapter, $id]])->assertJsonPath('msg', '排序已保存');
|
|
|
|
|
$this->assertSame([$chapter, $id], DB::table('course_content_evaluation_asks')->orderBy('sort')->pluck('id')->all());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testTextAnswersArePaginatedAndZeroRemainsVisible(): void
|
|
|
|
|
{
|
|
|
|
|
for ($i = 0; $i < 22; $i++) DB::table('course_content_evaluation_forms')->insert(['course_content_evaluation_id' => 10, 'data' => json_encode([['id' => 5, 'value' => $i === 0 ? '0' : '建议' . $i]])]);
|
|
|
|
|
$response = $this->getJson('/api/admin/course-content-evaluation-form/text-answers?course_content_evaluation_id=10&question_id=5&page=2&page_size=20')->assertJsonPath('total', 22);
|
|
|
|
|
$this->assertCount(2, $response->json('data'));
|
|
|
|
|
$this->assertSame('0', $response->json('data.1.text'));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testNewSurveyCanBeCreatedAndMigrationRolledBack(): void
|
|
|
|
|
{
|
|
|
|
|
$this->postJson('/api/admin/course-content-evaluations/save', ['title' => '新问卷', 'status' => 0])->assertJsonPath('title', '新问卷');
|
|
|
|
|
(require database_path('migrations/2026_10_09_000001_extend_survey_questions_and_snapshots.php'))->down();
|
|
|
|
|
$this->assertFalse(Schema::hasColumn('course_content_evaluation_forms', 'snapshot'));
|
|
|
|
|
$this->assertFalse(Schema::hasColumn('course_content_evaluation_asks', 'config'));
|
|
|
|
|
}
|
|
|
|
|
}
|