@ -1,361 +1,469 @@
import { Response } from 'miragejs' ;
import { authenticateSession , invalidateSession } from 'ember-simple-auth/test-support' ;
import { beforeEach , describe , it } from 'mocha' ;
import { click , currentRouteName , currentURL , fillIn , find , findAll } from '@ember/test-helpers' ;
import { expect } from 'chai' ;
import { setupApplicationTest } from 'ember-mocha' ;
import { setupMirage } from 'ember-cli-mirage/test-support' ;
import { visit } from '../helpers/visit' ;
import { Response } from 'miragejs' ;
// 导入Ember Simple Auth的测试支持工具: 用于认证和失效会话
import { authenticateSession , invalidateSession } from 'ember-simple-auth/test-support' ;
// 导入Mocha测试框架的钩子和断言方法
import { beforeEach , describe , it } from 'mocha' ;
// 导入Ember测试辅助函数: 用于模拟用户交互和获取DOM元素
import { click , currentRouteName , currentURL , fillIn , find , findAll } from '@ember/test-helpers' ;
// 导入Chai断言库
import { expect } from 'chai' ;
// 导入Ember应用测试设置工具
import { setupApplicationTest } from 'ember-mocha' ;
// 导入Mirage JS的测试支持工具
import { setupMirage } from 'ember-cli-mirage/test-support' ;
// 导入自定义的访问页面辅助函数
import { visit } from '../helpers/visit' ;
// 描述"标签( Tags) "验收测试套件
describe ( 'Acceptance: Tags' , function ( ) {
// 设置应用测试钩子和Mirage模拟服务器
let hooks = setupApplicationTest ( ) ;
setupMirage ( hooks ) ;
// 测试用例:未认证用户访问标签页时重定向到登录页
it ( 'redirects to signin when not authenticated' , async function ( ) {
// 使当前会话失效(模拟未登录状态)
await invalidateSession ( ) ;
// 访问标签页面
await visit ( '/tags' ) ;
// 断言当前URL为登录页
expect ( currentURL ( ) ) . to . equal ( '/signin' ) ;
} ) ;
// 测试用例: 贡献者( Contributor) 角色用户访问标签页时重定向到文章页
it ( 'redirects to posts page when authenticated as contributor' , async function ( ) {
let role = this . server . create ( 'role' , { name : 'Contributor' } ) ;
this . server . create ( 'user' , { roles : [ role ] , slug : 'test-user' } ) ;
// 创建"Contributor"角色
let role = this . server . create ( 'role' , { name : 'Contributor' } ) ;
// 创建具有该角色的用户
this . server . create ( 'user' , { roles : [ role ] , slug : 'test-user' } ) ;
// 认证当前会话(模拟登录)
await authenticateSession ( ) ;
// 访问标签页面
await visit ( '/tags' ) ;
// 断言当前URL为文章页
expect ( currentURL ( ) , 'currentURL' ) . to . equal ( '/posts' ) ;
} ) ;
// 测试用例: 作者( Author) 角色用户访问标签页时重定向到站点设置页
it ( 'redirects to site page when authenticated as author' , async function ( ) {
let role = this . server . create ( 'role' , { name : 'Author' } ) ;
this . server . create ( 'user' , { roles : [ role ] , slug : 'test-user' } ) ;
// 创建"Author"角色
let role = this . server . create ( 'role' , { name : 'Author' } ) ;
// 创建具有该角色的用户
this . server . create ( 'user' , { roles : [ role ] , slug : 'test-user' } ) ;
// 认证当前会话
await authenticateSession ( ) ;
// 访问标签页面
await visit ( '/tags' ) ;
// 断言当前URL为站点设置页
expect ( currentURL ( ) , 'currentURL' ) . to . equal ( '/site' ) ;
} ) ;
// 描述"以管理员( Administrator) 身份登录"的测试场景
describe ( 'when logged in as administrator' , function ( ) {
// 每个测试用例执行前的准备工作
beforeEach ( async function ( ) {
let role = this . server . create ( 'role' , { name : 'Administrator' } ) ;
this . server . create ( 'user' , { roles : [ role ] } ) ;
// 创建"Administrator"角色
let role = this . server . create ( 'role' , { name : 'Administrator' } ) ;
// 创建具有该角色的用户
this . server . create ( 'user' , { roles : [ role ] } ) ;
// 认证当前会话
await authenticateSession ( ) ;
} ) ;
// 测试用例:分别列出公开标签和内部标签
it ( 'lists public and internal tags separately' , async function ( ) {
this . server . create ( 'tag' , { name : 'B - Third' , slug : 'third' } ) ;
this . server . create ( 'tag' , { name : 'Z - Last' , slug : 'last' } ) ;
this . server . create ( 'tag' , { name : '!A - Second' , slug : 'second' } ) ;
this . server . create ( 'tag' , { name : 'A - First' , slug : 'first' } ) ;
this . server . create ( 'tag' , { name : '#one' , slug : 'hash-one' , visibility : 'internal' } ) ;
this . server . create ( 'tag' , { name : '#two' , slug : 'hash-two' , visibility : 'internal' } ) ;
// 创建4个公开标签
this . server . create ( 'tag' , { name : 'B - Third' , slug : 'third' } ) ;
this . server . create ( 'tag' , { name : 'Z - Last' , slug : 'last' } ) ;
this . server . create ( 'tag' , { name : '!A - Second' , slug : 'second' } ) ;
this . server . create ( 'tag' , { name : 'A - First' , slug : 'first' } ) ;
// 创建2个内部标签
this . server . create ( 'tag' , { name : '#one' , slug : 'hash-one' , visibility : 'internal' } ) ;
this . server . create ( 'tag' , { name : '#two' , slug : 'hash-two' , visibility : 'internal' } ) ;
// 访问标签页面
await visit ( 'tags' ) ;
// it loads tags list
// 断言页面成功加载( 当前URL为标签页)
expect ( currentURL ( ) , 'currentURL' ) . to . equal ( 'tags' ) ;
// it highlights nav menu
// 断言导航菜单中"标签"项处于激活状态
expect ( find ( '[data-test-nav="tags"]' ) , 'highlights nav menu item' )
. to . have . class ( 'active' ) ;
// it defaults to public tags
// 断言默认显示公开标签(公开标签按钮处于激活状态)
expect ( find ( '[data-test-tags-nav="public"]' ) ) . to . have . attr ( 'data-test-active' ) ;
expect ( find ( '[data-test-tags-nav="internal"]' ) ) . to . not . have . attr ( 'data-test-active' ) ;
// it lists all public tags
// 断言公开标签列表数量为4
expect ( findAll ( '[data-test-tag]' ) , 'public tag list count' )
. to . have . length ( 4 ) ;
// tags are in correct order
// 断言标签按正确顺序排序(按名称排序)
let tags = findAll ( '[data-test-tag]' ) ;
expect ( tags [ 0 ] . querySelector ( '[data-test-tag-name]' ) ) . to . have . trimmed . text ( 'A - First' ) ;
expect ( tags [ 1 ] . querySelector ( '[data-test-tag-name]' ) ) . to . have . trimmed . text ( '!A - Second' ) ;
expect ( tags [ 2 ] . querySelector ( '[data-test-tag-name]' ) ) . to . have . trimmed . text ( 'B - Third' ) ;
expect ( tags [ 3 ] . querySelector ( '[data-test-tag-name]' ) ) . to . have . trimmed . text ( 'Z - Last' ) ;
// can switch to internal tags
// 切换到内部标签视图
await click ( '[data-test-tags-nav="internal"]' ) ;
// 断言内部标签列表数量为2
expect ( findAll ( '[data-test-tag]' ) , 'internal tag list count' ) . to . have . length ( 2 ) ;
} ) ;
// 测试用例:可以添加标签
it ( 'can add tags' , async function ( ) {
// 访问标签页面
await visit ( 'tags' ) ;
// 断言初始时没有标签
expect ( findAll ( '[data-test-tag]' ) ) . to . have . length ( 0 ) ;
// 点击"新建标签"按钮
await click ( '[data-test-button="new-tag"]' ) ;
// 断言跳转到新建标签页面
expect ( currentURL ( ) ) . to . equal ( '/tags/new' ) ;
// 填写标签名称和slug
await fillIn ( '[data-test-input="tag-name"]' , 'New tag name' ) ;
await fillIn ( '[data-test-input="tag-slug"]' , 'new-tag-slug' ) ;
// 点击保存按钮
await click ( '[data-test-button="save"]' ) ;
// 点击返回标签列表链接
await click ( '[data-test-link="tags-back"]' ) ;
// 断言标签列表中新增了一个标签
expect ( findAll ( '[data-test-tag]' ) ) . to . have . length ( 1 ) ;
// 断言标签名称正确
expect ( find ( '[data-test-tag] [data-test-tag-name]' ) ) . to . have . trimmed . text ( 'New tag name' ) ;
// 断言标签slug正确
expect ( find ( '[data-test-tag] [data-test-tag-slug]' ) ) . to . have . trimmed . text ( 'new-tag-slug' ) ;
// 断言关联文章数量为0
expect ( find ( '[data-test-tag] [data-test-tag-count]' ) ) . to . have . trimmed . text ( '0 posts' ) ;
} ) ;
// 测试用例:可以编辑标签
it ( 'can edit tags' , async function ( ) {
const tag = this . server . create ( 'tag' , { name : 'To be edited' , slug : 'to-be-edited' } ) ;
// 创建一个待编辑的标签
const tag = this . server . create ( 'tag' , { name : 'To be edited' , slug : 'to-be-edited' } ) ;
// 访问标签页面
await visit ( 'tags' ) ;
// 点击标签名称进入编辑页
await click ( ` [data-test-tag=" ${ tag . id } "] [data-test-tag-name] ` ) ;
// it maintains active state in nav menu
// 断言导航菜单中"标签"项仍处于激活状态
expect ( find ( '[data-test-nav="tags"]' ) , 'highlights nav menu item' )
. to . have . class ( 'active' ) ;
// 断言当前URL为标签编辑页
expect ( currentURL ( ) ) . to . equal ( '/tags/to-be-edited' ) ;
// 断言表单中初始值正确
expect ( find ( '[data-test-input="tag-name"]' ) ) . to . have . value ( 'To be edited' ) ;
expect ( find ( '[data-test-input="tag-slug"]' ) ) . to . have . value ( 'to-be-edited' ) ;
// 修改标签名称和slug
await fillIn ( '[data-test-input="tag-name"]' , 'New tag name' ) ;
await fillIn ( '[data-test-input="tag-slug"]' , 'new-tag-slug' ) ;
// 点击保存按钮
await click ( '[data-test-button="save"]' ) ;
// 从数据库中获取保存后的标签,断言数据已更新
const savedTag = this . server . db . tags . find ( tag . id ) ;
expect ( savedTag . name , 'saved tag name' ) . to . equal ( 'New tag name' ) ;
expect ( savedTag . slug , 'saved tag slug' ) . to . equal ( 'new-tag-slug' ) ;
// 点击返回标签列表链接
await click ( '[data-test-link="tags-back"]' ) ;
// 断言标签列表中显示更新后的标签信息
const tagListItem = find ( '[data-test-tag]' ) ;
expect ( tagListItem . querySelector ( '[data-test-tag-name]' ) ) . to . have . trimmed . text ( 'New tag name' ) ;
expect ( tagListItem . querySelector ( '[data-test-tag-slug]' ) ) . to . have . trimmed . text ( 'new-tag-slug' ) ;
} ) ;
// 测试用例:编辑标签时不会创建重复项
it ( 'does not create duplicates when editing a tag' , async function ( ) {
const tag = this . server . create ( 'tag' , { name : 'To be edited' , slug : 'to-be-edited' } ) ;
// 创建一个待编辑的标签
const tag = this . server . create ( 'tag' , { name : 'To be edited' , slug : 'to-be-edited' } ) ;
// 访问标签页面
await visit ( 'tags' ) ;
// Verify we start with one tag
// 断言初始时只有一个标签
expect ( findAll ( '[data-test-tag]' ) ) . to . have . length ( 1 ) ;
// 点击标签名称进入编辑页
await click ( ` [data-test-tag=" ${ tag . id } "] [data-test-tag-name] ` ) ;
// 修改标签名称
await fillIn ( '[data-test-input="tag-name"]' , 'Edited Tag Name' ) ;
// 点击保存按钮
await click ( '[data-test-button="save"]' ) ;
// 点击返回标签列表链接
await click ( '[data-test-link="tags-back"]' ) ;
// Verify we still have only one tag after editing (no duplicates)
// 断言编辑后仍只有一个标签(无重复)
expect ( findAll ( '[data-test-tag]' ) ) . to . have . length ( 1 ) ;
// 断言标签名称已更新
expect ( find ( '[data-test-tag] [data-test-tag-name]' ) ) . to . have . trimmed . text ( 'Edited Tag Name' ) ;
} ) ;
// 测试用例:可以删除标签
it ( 'can delete tags' , async function ( ) {
const tag = this . server . create ( 'tag' , { name : 'To be edited' , slug : 'to-be-edited' } ) ;
this . server . create ( 'post' , { tags : [ tag ] } ) ;
// 创建一个待删除的标签
const tag = this . server . create ( 'tag' , { name : 'To be edited' , slug : 'to-be-edited' } ) ;
// 创建一篇关联该标签的文章
this . server . create ( 'post' , { tags : [ tag ] } ) ;
// 访问标签页面
await visit ( 'tags' ) ;
// 点击标签名称进入编辑页
await click ( ` [data-test-tag=" ${ tag . id } "] [data-test-tag-name] ` ) ;
// 点击删除标签按钮
await click ( '[data-test-button="delete-tag"]' ) ;
// 定义删除确认弹窗选择器
const tagModal = '[data-test-modal="confirm-delete-tag"]' ;
// 断言弹窗已显示
expect ( find ( tagModal ) ) . to . exist ;
// 断言弹窗中显示正确的关联文章数量
expect ( find ( ` ${ tagModal } [data-test-text="posts-count"] ` ) )
. to . have . trimmed . text ( '1 post' ) ;
// 点击确认删除按钮
await click ( ` ${ tagModal } [data-test-button="confirm"] ` ) ;
// 断言弹窗已关闭
expect ( find ( tagModal ) ) . to . not . exist ;
// 断言返回标签列表页
expect ( currentURL ( ) ) . to . equal ( '/tags' ) ;
// 断言标签已被删除(列表为空)
expect ( findAll ( '[data-test-tag]' ) ) . to . have . length ( 0 ) ;
} ) ;
// 测试用例: 可以通过URL中的slug访问标签
it ( 'can load tag via slug in url' , async function ( ) {
this . server . create ( 'tag' , { name : 'To be edited' , slug : 'to-be-edited' } ) ;
// 创建一个标签
this . server . create ( 'tag' , { name : 'To be edited' , slug : 'to-be-edited' } ) ;
// 直接通过slug访问标签编辑页
await visit ( 'tags/to-be-edited' ) ;
// 断言当前URL正确
expect ( currentURL ( ) ) . to . equal ( 'tags/to-be-edited' ) ;
// 断言表单中显示正确的标签信息
expect ( find ( '[data-test-input="tag-name"]' ) ) . to . have . value ( 'To be edited' ) ;
expect ( find ( '[data-test-input="tag-slug"]' ) ) . to . have . value ( 'to-be-edited' ) ;
} ) ;
// 测试用例: 访问不存在的标签时重定向到404页面
it ( 'redirects to 404 when tag does not exist' , async function ( ) {
// 模拟请求不存在的标签时返回404错误
this . server . get ( '/tags/slug/unknown/' , function ( ) {
return new Response ( 404 , { 'Content-Type' : 'application/json' } , { errors : [ { message : 'Tag not found.' , type : 'NotFoundError' } ] } ) ;
return new Response ( 404 , { 'Content-Type' : 'application/json' } , {
errors : [ { message : 'Tag not found.' , type : 'NotFoundError' } ]
} ) ;
} ) ;
// 访问不存在的标签页面
await visit ( 'tags/unknown' ) ;
// 断言当前路由为404错误页
expect ( currentRouteName ( ) ) . to . equal ( 'error404' ) ;
// 断言URL保持不变( 显示错误的URL)
expect ( currentURL ( ) ) . to . equal ( '/tags/unknown' ) ;
} ) ;
// 测试用例:创建新标签时导航菜单中"标签"项保持激活状态
it ( 'maintains active state in nav menu when creating a new tag' , async function ( ) {
// 访问新建标签页面
await visit ( 'tags/new' ) ;
// 断言当前URL正确
expect ( currentURL ( ) ) . to . equal ( 'tags/new' ) ;
// 断言导航菜单中"标签"项处于激活状态
expect ( find ( '[data-test-nav="tags"]' ) , 'highlights nav menu item' )
. to . have . class ( 'active' ) ;
} ) ;
} ) ;
// 描述"以编辑者( Editor) 身份登录"的测试场景
describe ( 'as an editor' , function ( ) {
// 每个测试用例执行前的准备工作
beforeEach ( async function ( ) {
let role = this . server . create ( 'role' , { name : 'Editor' } ) ;
this . server . create ( 'user' , { roles : [ role ] } ) ;
// 创建"Editor"角色
let role = this . server . create ( 'role' , { name : 'Editor' } ) ;
// 创建具有该角色的用户
this . server . create ( 'user' , { roles : [ role ] } ) ;
// 认证当前会话
await authenticateSession ( ) ;
} ) ;
it ( 'lists public and internal tags separately' , async function ( ) {
this . server . create ( 'tag' , { name : 'B - Third' , slug : 'third' } ) ;
this . server . create ( 'tag' , { name : 'Z - Last' , slug : 'last' } ) ;
this . server . create ( 'tag' , { name : '!A - Second' , slug : 'second' } ) ;
this . server . create ( 'tag' , { name : 'A - First' , slug : 'first' } ) ;
this . server . create ( 'tag' , { name : '#one' , slug : 'hash-one' , visibility : 'internal' } ) ;
this . server . create ( 'tag' , { name : '#two' , slug : 'hash-two' , visibility : 'internal' } ) ;
// 测试用例:分别列出公开标签和内部标签(与管理员权限一致)
it ( 'lists public and internal tags separately' , async function ( ) {
// 创建4个公开标签和2个内部标签( 同管理员测试用例)
this . server . create ( 'tag' , { name : 'B - Third' , slug : 'third' } ) ;
this . server . create ( 'tag' , { name : 'Z - Last' , slug : 'last' } ) ;
this . server . create ( 'tag' , { name : '!A - Second' , slug : 'second' } ) ;
this . server . create ( 'tag' , { name : 'A - First' , slug : 'first' } ) ;
this . server . create ( 'tag' , { name : '#one' , slug : 'hash-one' , visibility : 'internal' } ) ;
this . server . create ( 'tag' , { name : '#two' , slug : 'hash-two' , visibility : 'internal' } ) ;
// 访问标签页面
await visit ( 'tags' ) ;
// it loads tags list
// 断言页面成功加载
expect ( currentURL ( ) , 'currentURL' ) . to . equal ( 'tags' ) ;
// it highlights nav menu
// 断言导航菜单激活状态
expect ( find ( '[data-test-nav="tags"]' ) , 'highlights nav menu item' )
. to . have . class ( 'active' ) ;
// it defaults to public tags
// 断言默认显示公开标签
expect ( find ( '[data-test-tags-nav="public"]' ) ) . to . have . attr ( 'data-test-active' ) ;
expect ( find ( '[data-test-tags-nav="internal"]' ) ) . to . not . have . attr ( 'data-test-active' ) ;
// it lists all public tags
// 断言公开标签数量
expect ( findAll ( '[data-test-tag]' ) , 'public tag list count' )
. to . have . length ( 4 ) ;
// tags are in correct order
// 断言标签排序正确
let tags = findAll ( '[data-test-tag]' ) ;
expect ( tags [ 0 ] . querySelector ( '[data-test-tag-name]' ) ) . to . have . trimmed . text ( 'A - First' ) ;
expect ( tags [ 1 ] . querySelector ( '[data-test-tag-name]' ) ) . to . have . trimmed . text ( '!A - Second' ) ;
expect ( tags [ 2 ] . querySelector ( '[data-test-tag-name]' ) ) . to . have . trimmed . text ( 'B - Third' ) ;
expect ( tags [ 3 ] . querySelector ( '[data-test-tag-name]' ) ) . to . have . trimmed . text ( 'Z - Last' ) ;
// can switch to internal tags
// 切换到内部标签
await click ( '[data-test-tags-nav="internal"]' ) ;
// 断言内部标签数量
expect ( findAll ( '[data-test-tag]' ) , 'internal tag list count' ) . to . have . length ( 2 ) ;
} ) ;
// 测试用例:可以编辑标签(与管理员权限一致)
it ( 'can edit tags' , async function ( ) {
const tag = this . server . create ( 'tag' , { name : 'To be edited' , slug : 'to-be-edited' } ) ;
// 创建待编辑标签
const tag = this . server . create ( 'tag' , { name : 'To be edited' , slug : 'to-be-edited' } ) ;
// 访问标签页面并进入编辑页
await visit ( 'tags' ) ;
await click ( ` [data-test-tag=" ${ tag . id } "] [data-test-tag-name] ` ) ;
// it maintains active state in nav menu
// 断言导航菜单激活状态
expect ( find ( '[data-test-nav="tags"]' ) , 'highlights nav menu item' )
. to . have . class ( 'active' ) ;
// 断言当前URL
expect ( currentURL ( ) ) . to . equal ( '/tags/to-be-edited' ) ;
// 断言初始表单值
expect ( find ( '[data-test-input="tag-name"]' ) ) . to . have . value ( 'To be edited' ) ;
expect ( find ( '[data-test-input="tag-slug"]' ) ) . to . have . value ( 'to-be-edited' ) ;
// 修改并保存标签
await fillIn ( '[data-test-input="tag-name"]' , 'New tag name' ) ;
await fillIn ( '[data-test-input="tag-slug"]' , 'new-tag-slug' ) ;
await click ( '[data-test-button="save"]' ) ;
// 断言数据已更新
const savedTag = this . server . db . tags . find ( tag . id ) ;
expect ( savedTag . name , 'saved tag name' ) . to . equal ( 'New tag name' ) ;
expect ( savedTag . slug , 'saved tag slug' ) . to . equal ( 'new-tag-slug' ) ;
// 返回列表页并断言显示正确
await click ( '[data-test-link="tags-back"]' ) ;
const tagListItem = find ( '[data-test-tag]' ) ;
expect ( tagListItem . querySelector ( '[data-test-tag-name]' ) ) . to . have . trimmed . text ( 'New tag name' ) ;
expect ( tagListItem . querySelector ( '[data-test-tag-slug]' ) ) . to . have . trimmed . text ( 'new-tag-slug' ) ;
} ) ;
// 测试用例:可以删除标签(与管理员权限一致)
it ( 'can delete tags' , async function ( ) {
const tag = this . server . create ( 'tag' , { name : 'To be edited' , slug : 'to-be-edited' } ) ;
this . server . create ( 'post' , { tags : [ tag ] } ) ;
// 创建待删除标签及关联文章
const tag = this . server . create ( 'tag' , { name : 'To be edited' , slug : 'to-be-edited' } ) ;
this . server . create ( 'post' , { tags : [ tag ] } ) ;
// 访问标签页面并进入编辑页
await visit ( 'tags' ) ;
await click ( ` [data-test-tag=" ${ tag . id } "] [data-test-tag-name] ` ) ;
// 点击删除按钮
await click ( '[data-test-button="delete-tag"]' ) ;
const tagModal = '[data-test-modal="confirm-delete-tag"]' ;
// 断言弹窗显示及内容正确
expect ( find ( tagModal ) ) . to . exist ;
expect ( find ( ` ${ tagModal } [data-test-text="posts-count"] ` ) )
. to . have . trimmed . text ( '1 post' ) ;
// 确认删除
await click ( ` ${ tagModal } [data-test-button="confirm"] ` ) ;
// 断言标签已删除
expect ( find ( tagModal ) ) . to . not . exist ;
expect ( currentURL ( ) ) . to . equal ( '/tags' ) ;
expect ( findAll ( '[data-test-tag]' ) ) . to . have . length ( 0 ) ;
} ) ;
} ) ;
// 描述"以超级编辑者( Super Editor) 身份登录"的测试场景
describe ( 'as a super editor' , function ( ) {
// 每个测试用例执行前的准备工作
beforeEach ( async function ( ) {
let role = this . server . create ( 'role' , { name : 'Super Editor' } ) ;
this . server . create ( 'user' , { roles : [ role ] } ) ;
// 创建"Super Editor"角色
let role = this . server . create ( 'role' , { name : 'Super Editor' } ) ;
// 创建具有该角色的用户
this . server . create ( 'user' , { roles : [ role ] } ) ;
// 认证当前会话
await authenticateSession ( ) ;
} ) ;
it ( 'lists public and internal tags separately' , async function ( ) {
this . server . create ( 'tag' , { name : 'B - Third' , slug : 'third' } ) ;
this . server . create ( 'tag' , { name : 'Z - Last' , slug : 'last' } ) ;
this . server . create ( 'tag' , { name : '!A - Second' , slug : 'second' } ) ;
this . server . create ( 'tag' , { name : 'A - First' , slug : 'first' } ) ;
this . server . create ( 'tag' , { name : '#one' , slug : 'hash-one' , visibility : 'internal' } ) ;
this . server . create ( 'tag' , { name : '#two' , slug : 'hash-two' , visibility : 'internal' } ) ;
// 测试用例:分别列出公开标签和内部标签(与管理员权限一致)
it ( 'lists public and internal tags separately' , async function ( ) {
// 创建4个公开标签和2个内部标签( 同管理员测试用例)
this . server . create ( 'tag' , { name : 'B - Third' , slug : 'third' } ) ;
this . server . create ( 'tag' , { name : 'Z - Last' , slug : 'last' } ) ;
this . server . create ( 'tag' , { name : '!A - Second' , slug : 'second' } ) ;
this . server . create ( 'tag' , { name : 'A - First' , slug : 'first' } ) ;
this . server . create ( 'tag' , { name : '#one' , slug : 'hash-one' , visibility : 'internal' } ) ;
this . server . create ( 'tag' , { name : '#two' , slug : 'hash-two' , visibility : 'internal' } ) ;
// 访问标签页面
await visit ( 'tags' ) ;
// it loads tags list
// 断言页面加载及标签展示正确(与管理员测试用例一致)
expect ( currentURL ( ) , 'currentURL' ) . to . equal ( 'tags' ) ;
// it highlights nav menu
expect ( find ( '[data-test-nav="tags"]' ) , 'highlights nav menu item' )
. to . have . class ( 'active' ) ;
// it defaults to public tags
expect ( find ( '[data-test-tags-nav="public"]' ) ) . to . have . attr ( 'data-test-active' ) ;
expect ( find ( '[data-test-tags-nav="internal"]' ) ) . to . not . have . attr ( 'data-test-active' ) ;
// it lists all public tags
expect ( findAll ( '[data-test-tag]' ) , 'public tag list count' )
. to . have . length ( 4 ) ;
// tags are in correct order
let tags = findAll ( '[data-test-tag]' ) ;
expect ( tags [ 0 ] . querySelector ( '[data-test-tag-name]' ) ) . to . have . trimmed . text ( 'A - First' ) ;
expect ( tags [ 1 ] . querySelector ( '[data-test-tag-name]' ) ) . to . have . trimmed . text ( '!A - Second' ) ;
expect ( tags [ 2 ] . querySelector ( '[data-test-tag-name]' ) ) . to . have . trimmed . text ( 'B - Third' ) ;
expect ( tags [ 3 ] . querySelector ( '[data-test-tag-name]' ) ) . to . have . trimmed . text ( 'Z - Last' ) ;
// can switch to internal tags
await click ( '[data-test-tags-nav="internal"]' ) ;
expect ( findAll ( '[data-test-tag]' ) , 'internal tag list count' ) . to . have . length ( 2 ) ;
} ) ;
// 测试用例:可以编辑标签(与管理员权限一致)
it ( 'can edit tags' , async function ( ) {
const tag = this . server . create ( 'tag' , { name : 'To be edited' , slug : 'to-be-edited' } ) ;
// 创建待编辑标签(测试步骤与管理员测试用例一致)
const tag = this . server . create ( 'tag' , { name : 'To be edited' , slug : 'to-be-edited' } ) ;
await visit ( 'tags' ) ;
await click ( ` [data-test-tag=" ${ tag . id } "] [data-test-tag-name] ` ) ;
// it maintains active state in nav menu
expect ( find ( '[data-test-nav="tags"]' ) , 'highlights nav menu item' )
. to . have . class ( 'active' ) ;
expect ( currentURL ( ) ) . to . equal ( '/tags/to-be-edited' ) ;
expect ( find ( '[data-test-input="tag-name"]' ) ) . to . have . value ( 'To be edited' ) ;
expect ( find ( '[data-test-input="tag-slug"]' ) ) . to . have . value ( 'to-be-edited' ) ;
@ -368,21 +476,21 @@ describe('Acceptance: Tags', function () {
expect ( savedTag . slug , 'saved tag slug' ) . to . equal ( 'new-tag-slug' ) ;
await click ( '[data-test-link="tags-back"]' ) ;
const tagListItem = find ( '[data-test-tag]' ) ;
expect ( tagListItem . querySelector ( '[data-test-tag-name]' ) ) . to . have . trimmed . text ( 'New tag name' ) ;
expect ( tagListItem . querySelector ( '[data-test-tag-slug]' ) ) . to . have . trimmed . text ( 'new-tag-slug' ) ;
} ) ;
// 测试用例:可以删除标签(与管理员权限一致)
it ( 'can delete tags' , async function ( ) {
const tag = this . server . create ( 'tag' , { name : 'To be edited' , slug : 'to-be-edited' } ) ;
this . server . create ( 'post' , { tags : [ tag ] } ) ;
// 创建待删除标签及关联文章(测试步骤与管理员测试用例一致)
const tag = this . server . create ( 'tag' , { name : 'To be edited' , slug : 'to-be-edited' } ) ;
this . server . create ( 'post' , { tags : [ tag ] } ) ;
await visit ( 'tags' ) ;
await click ( ` [data-test-tag=" ${ tag . id } "] [data-test-tag-name] ` ) ;
await click ( '[data-test-button="delete-tag"]' ) ;
const tagModal = '[data-test-modal="confirm-delete-tag"]' ;
expect ( find ( tagModal ) ) . to . exist ;
@ -396,4 +504,4 @@ describe('Acceptance: Tags', function () {
expect ( findAll ( '[data-test-tag]' ) ) . to . have . length ( 0 ) ;
} ) ;
} ) ;
} ) ;
} ) ;