mirror of
https://github.com/linux-odyssey/linux-odyssey.git
synced 2026-11-05 19:20:12 +08:00
feat Automation Tests - Updates (#87)
- Change spec name - Add spec and complete all quests - Add Icon (totem version) - Add some id for tests - Add answer. sh for all quests Not yet added verifying the buttons function and other pages
This commit is contained in:
18 files changed
+214
-41
No files matched your search
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/icon_totem.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Linux Odyssey</title>
|
<title>Linux Odyssey</title>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<svg width="638" height="732" viewBox="0 0 638 732" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<path d="M0 0H638V732H0V0Z" fill="url(#pattern0)"/>
|
||||||
|
<defs>
|
||||||
|
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||||
|
<use xlink:href="#image0_379_14" transform="matrix(0.00126582 0 0 0.00110327 0 -0.000333748)"/>
|
||||||
|
</pattern>
|
||||||
|
<image id="image0_379_14" width="790" height="907" xlink:href="data:image/png;base64,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 truncated
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 630 KiB |
@@ -89,7 +89,12 @@ const handleChange = () => {
|
|||||||
<div
|
<div
|
||||||
class="bg-bg border-8 border-bg-primary flex flex-1 flex-col items-center justify-center rounded-3xl p-10"
|
class="bg-bg border-8 border-bg-primary flex flex-1 flex-col items-center justify-center rounded-3xl p-10"
|
||||||
>
|
>
|
||||||
<h1 class="text-text-primary text-3xl font-black mb-2">{{ title }}</h1>
|
<div class="w-full flex items-center justify-center mb-2 gap-3">
|
||||||
|
<img src="../img/icon_totem.svg" class="h-10" />
|
||||||
|
<h1 class="text-text-primary text-3xl font-black" id="title">
|
||||||
|
{{ title }}
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
<div class="text-error inline-flex justify-center items-center md:hidden">
|
<div class="text-error inline-flex justify-center items-center md:hidden">
|
||||||
<font-awesome-icon
|
<font-awesome-icon
|
||||||
:icon="['fas', 'circle-exclamation']"
|
:icon="['fas', 'circle-exclamation']"
|
||||||
@@ -163,6 +168,7 @@ const handleChange = () => {
|
|||||||
/>
|
/>
|
||||||
<label
|
<label
|
||||||
class="text-sm font-normal text-text-secondary"
|
class="text-sm font-normal text-text-secondary"
|
||||||
|
id="NameRules"
|
||||||
v-if="type === 'username' || type === 'register'"
|
v-if="type === 'username' || type === 'register'"
|
||||||
>
|
>
|
||||||
<p>可用小寫字母、數字、"_"和"-"</p>
|
<p>可用小寫字母、數字、"_"和"-"</p>
|
||||||
|
|||||||
@@ -78,15 +78,16 @@ onMounted(async () => {
|
|||||||
class="text-border h-full w-full"
|
class="text-border h-full w-full"
|
||||||
/>
|
/>
|
||||||
</button> -->
|
</button> -->
|
||||||
|
<img src="../img/icon_totem.svg" class="h-5" />
|
||||||
<button
|
<button
|
||||||
id="HeaderText"
|
id="GameTitle"
|
||||||
class="text-text-primary inline-block font-bold whitespace-nowrap"
|
class="text-text-primary inline-block font-bold whitespace-nowrap"
|
||||||
style="font-size: 2vh"
|
style="font-size: 2vh"
|
||||||
>
|
>
|
||||||
Linux Odyssey
|
Linux Odyssey
|
||||||
</button>
|
</button>
|
||||||
<p
|
<p
|
||||||
id="HeaderText"
|
id="QuestTitle"
|
||||||
class="text-text inline-block font-bold whitespace-nowrap"
|
class="text-text inline-block font-bold whitespace-nowrap"
|
||||||
style="font-size: 2vh"
|
style="font-size: 2vh"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<svg width="638" height="732" viewBox="0 0 638 732" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<path d="M0 0H638V732H0V0Z" fill="url(#pattern0)"/>
|
||||||
|
<defs>
|
||||||
|
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||||
|
<use xlink:href="#image0_379_14" transform="matrix(0.00126582 0 0 0.00110327 0 -0.000333748)"/>
|
||||||
|
</pattern>
|
||||||
|
<image id="image0_379_14" width="790" height="907" xlink:href="data:image/png;base64,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 truncated
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 630 KiB |
@@ -0,0 +1,3 @@
|
|||||||
|
echo start
|
||||||
|
echo example
|
||||||
|
echo How are you
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
echo start
|
||||||
|
cat hello.txt
|
||||||
|
cat world.txt
|
||||||
|
echo continue
|
||||||
|
cp hello.txt hello2.txt
|
||||||
|
cat hello2.txt
|
||||||
|
cp world.txt world2.txt
|
||||||
|
cat world2.txt
|
||||||
|
cp -r notes notes2
|
||||||
|
ls notes2
|
||||||
|
cp hello.txt world.txt
|
||||||
|
cat world.txt
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
echo start
|
||||||
|
touch hello.txt
|
||||||
|
ls
|
||||||
|
cat hello.txt
|
||||||
|
touch world.txt
|
||||||
|
ls
|
||||||
|
mkdir notes
|
||||||
|
ls
|
||||||
|
cd notes
|
||||||
|
touch note.txt
|
||||||
|
ls
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
echo start
|
||||||
|
ls
|
||||||
|
cd folder1
|
||||||
|
ls
|
||||||
|
cd ..
|
||||||
|
cd folder2
|
||||||
|
ls
|
||||||
|
cd ..
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
echo start
|
||||||
|
echo hello
|
||||||
|
echo finish
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
echo help{enter}
|
echo help
|
||||||
ls {enter}
|
ls
|
||||||
cat forgotten_scroll.txt{enter}
|
cat forgotten_scroll.txt
|
||||||
echo Hello World!{enter}
|
echo Hello World
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
echo start
|
||||||
|
echo continue
|
||||||
|
mv hello.txt notes
|
||||||
|
ls
|
||||||
|
ls notes
|
||||||
|
echo continue
|
||||||
|
mv world.txt wow.txt
|
||||||
|
ls
|
||||||
|
mv notes docs
|
||||||
|
ls
|
||||||
|
echo hint
|
||||||
|
mv docs/hello.txt hi.txt
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
echo start
|
||||||
|
ls
|
||||||
|
cd folder1
|
||||||
|
cd ../folder2
|
||||||
|
ls ../folder1
|
||||||
|
pwd
|
||||||
|
ls ~
|
||||||
|
cd ~
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
echo start
|
||||||
|
ls
|
||||||
|
cat file1.txt
|
||||||
|
ls folder
|
||||||
|
cat folder/file.txt
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
echo start
|
||||||
|
rm hello.txt
|
||||||
|
ls
|
||||||
|
rm world.txt wow.txt
|
||||||
|
ls
|
||||||
|
rmdir empty
|
||||||
|
ls
|
||||||
|
rmdir notes
|
||||||
|
rm notes/note.txt
|
||||||
|
rmdir notes
|
||||||
|
ls trash
|
||||||
|
rm -r trash
|
||||||
|
ls
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
export default function checkLoginUI() {
|
export default function checkLoginUI() {
|
||||||
cy.get('h1.text-text-primary')
|
cy.get('#title').should('contain', 'Linux Odyssey').and('be.visible')
|
||||||
.should('contain', 'Linux Odyssey')
|
|
||||||
.and('be.visible')
|
|
||||||
cy.CheckPlaceholder('#password', '密碼', 'Password')
|
cy.CheckPlaceholder('#password', '密碼', 'Password')
|
||||||
}
|
}
|
||||||
describe('example helloworld app', () => {
|
describe('example helloworld app', () => {
|
||||||
@@ -13,7 +11,7 @@ describe('example helloworld app', () => {
|
|||||||
it('Check Login Page Elements-Register', () => {
|
it('Check Login Page Elements-Register', () => {
|
||||||
checkLoginUI()
|
checkLoginUI()
|
||||||
cy.CheckPlaceholder('#username', '帳號名稱', 'Username')
|
cy.CheckPlaceholder('#username', '帳號名稱', 'Username')
|
||||||
cy.get('label.text-text-secondary').should('be.visible') // check the rules is displayed
|
cy.get('#NameRules').should('be.visible') // check the rules is displayed
|
||||||
cy.CheckPlaceholder('#email', '電子郵件', 'Email')
|
cy.CheckPlaceholder('#email', '電子郵件', 'Email')
|
||||||
cy.CheckTextElement(
|
cy.CheckTextElement(
|
||||||
'#CheckRegistered',
|
'#CheckRegistered',
|
||||||
@@ -79,15 +77,23 @@ describe('example helloworld app', () => {
|
|||||||
cy.PrepareForGame()
|
cy.PrepareForGame()
|
||||||
})
|
})
|
||||||
it('Check Header', () => {
|
it('Check Header', () => {
|
||||||
cy.get('#HeaderText').should('contain', 'Linux Odyssey').and('be.visible')
|
cy.get('#GameTitle').should('contain', 'Linux Odyssey').and('be.visible')
|
||||||
|
cy.get('#QuestTitle').should('contain', title).and('be.visible')
|
||||||
|
cy.get('#UsernameText')
|
||||||
|
.should('contain', Cypress.env('defaultAccount'))
|
||||||
|
.and('be.visible')
|
||||||
cy.findByRole('link', { name: 'Bug Report' }).should('be.visible')
|
cy.findByRole('link', { name: 'Bug Report' }).should('be.visible')
|
||||||
cy.findByRole('button', { name: 'Sign Out' }).should('be.visible')
|
cy.findByRole('button', { name: 'Sign Out' }).should('be.visible')
|
||||||
|
cy.findByRole('button', { name: 'Map' }).should('be.visible')
|
||||||
|
cy.findByRole('button', { name: 'LeaderBoard' }).should('be.visible')
|
||||||
|
cy.findByRole('link', { name: 'Survey' }).should('be.visible')
|
||||||
})
|
})
|
||||||
it('Check QuestInfo', () => {
|
it('Check QuestInfo', () => {
|
||||||
cy.get('#topic').should('contain', title)
|
cy.get('#topic').should('contain', title)
|
||||||
cy.get('#quest').find('p.text-text').should('have.length', 4)
|
cy.get('#topic').should('be.visible')
|
||||||
|
cy.get('#tasks').should('be.visible')
|
||||||
|
cy.get('#quest').find('p.text-text').should('have.length', 2)
|
||||||
cy.CheckTextElement('#tasks', '任務', 'Tasks:')
|
cy.CheckTextElement('#tasks', '任務', 'Tasks:')
|
||||||
cy.getQuestInfo('輸入 `echo help` 來朗誦咒語').should('be.visible')
|
|
||||||
})
|
})
|
||||||
it('Check Terminal', () => {
|
it('Check Terminal', () => {
|
||||||
cy.get('#terminal', { timeout: 20000 }).within(($terminal) => {
|
cy.get('#terminal', { timeout: 20000 }).within(($terminal) => {
|
||||||
@@ -114,6 +120,7 @@ describe('example helloworld app', () => {
|
|||||||
cy.CheckTextElement('#solution', '解答', 'Solution')
|
cy.CheckTextElement('#solution', '解答', 'Solution')
|
||||||
cy.CheckTextElement('#reset', '重來', 'Reset')
|
cy.CheckTextElement('#reset', '重來', 'Reset')
|
||||||
cy.CheckTextElement('#continue', '繼續', 'Continue')
|
cy.CheckTextElement('#continue', '繼續', 'Continue')
|
||||||
|
cy.CheckTextElement('#survey', '問卷', 'Survey')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
describe('Game Play', () => {
|
describe('Game Play', () => {
|
||||||
@@ -126,42 +133,31 @@ describe('example helloworld app', () => {
|
|||||||
.should('contain', '12345')
|
.should('contain', '12345')
|
||||||
.and('contain', 'zsh: command not found: 12345', { timeout: 50000 })
|
.and('contain', 'zsh: command not found: 12345', { timeout: 50000 })
|
||||||
})
|
})
|
||||||
it('Complete the Game(relating UI)', () => {
|
it('Complete the First Quest(relating UI)', () => {
|
||||||
// Stage1
|
cy.checkTaskInit()
|
||||||
cy.log('Stage1')
|
cy.InitTerminal()
|
||||||
cy.typeInCommand('echo start{enter}')
|
cy.typeInCommand('echo start{enter}')
|
||||||
cy.checkPending()
|
cy.checkPending()
|
||||||
cy.waitUntilActive()
|
cy.waitUntilActive()
|
||||||
cy.get('#Lbutton').should('be.visible').and('be.disabled')
|
cy.get('#Lbutton').should('be.visible').and('be.disabled')
|
||||||
cy.get('#Rbutton').should('be.visible').and('be.disabled')
|
cy.get('#Rbutton').should('be.visible').and('be.disabled')
|
||||||
cy.checkHint(1, 1)
|
cy.checkHint(1, 1)
|
||||||
cy.getQuestInfo('✓ 輸入 `echo start` 來開始教程').should('be.visible')
|
cy.getQuestInfo('✓ 輸入 echo start 來開始教程').should('be.visible')
|
||||||
cy.getQuestInfo('➤ 在終端機輸入 `echo hello`').should('be.visible')
|
cy.getQuestInfo('➤ 在終端機輸入 echo hello').should('be.visible')
|
||||||
// Stage2
|
|
||||||
cy.log('Stage2')
|
|
||||||
cy.typeInCommand('echo hello{enter}')
|
cy.typeInCommand('echo hello{enter}')
|
||||||
cy.checkPending()
|
cy.checkPending()
|
||||||
cy.waitUntilActive()
|
cy.waitUntilActive()
|
||||||
// cy.get('#tree')
|
|
||||||
// .get('a')
|
|
||||||
// .should('contain', 'forgotten_scroll.txt')
|
|
||||||
// .and('be.visible')
|
|
||||||
cy.get('#Lbutton').should('be.visible').and('be.enabled')
|
cy.get('#Lbutton').should('be.visible').and('be.enabled')
|
||||||
cy.get('#Rbutton').should('be.visible').and('be.disabled')
|
cy.get('#Rbutton').should('be.visible').and('be.disabled')
|
||||||
cy.checkHint(2, 2)
|
cy.checkHint(2, 2)
|
||||||
cy.get('#Lbutton').click()
|
cy.get('#Lbutton').click()
|
||||||
cy.get('#Rbutton').should('be.enabled')
|
cy.get('#Rbutton').should('be.enabled')
|
||||||
cy.getQuestInfo('✓ 在終端機輸入 `echo hello`').should('be.visible')
|
cy.getQuestInfo('✓ 在終端機輸入 echo hello').should('be.visible')
|
||||||
cy.getQuestInfo('➤ 結束關卡').should('be.visible')
|
cy.getQuestInfo('➤ 結束關卡').should('be.visible')
|
||||||
// Stage3
|
|
||||||
cy.log('Stage3')
|
|
||||||
cy.typeInCommand('echo finish{enter}')
|
cy.typeInCommand('echo finish{enter}')
|
||||||
cy.checkPending()
|
|
||||||
cy.waitUntilActive()
|
|
||||||
cy.getQuestInfo('✓ 結束關卡').should('be.visible')
|
|
||||||
cy.CheckTextElement('#QuestCompleted', '關卡完成!', 'Quest Completed!')
|
cy.CheckTextElement('#QuestCompleted', '關卡完成!', 'Quest Completed!')
|
||||||
cy.get('div[class="modal"]').find('p').should('be.visible')
|
cy.get('div[class="modal"]').find('p').should('be.visible')
|
||||||
cy.findByRole('link', { name: '填寫問卷' }).should('be.visible')
|
cy.get('#BacktoMap').should('be.visible').and('contain', '回到地圖')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/// <reference types="cypress" />
|
||||||
|
describe('Complete quests with only commands', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.PrepareForGame()
|
||||||
|
})
|
||||||
|
it('Complete quest : get-started', () => {
|
||||||
|
cy.CompleteStageWithCommands('get-started')
|
||||||
|
})
|
||||||
|
it('Complete quest : cast', () => {
|
||||||
|
cy.CompleteStageWithCommands('cast')
|
||||||
|
})
|
||||||
|
it('Complete quest : explore', () => {
|
||||||
|
cy.CompleteStageWithCommands('explore')
|
||||||
|
})
|
||||||
|
it('Complete quest : path', () => {
|
||||||
|
cy.CompleteStageWithCommands('path')
|
||||||
|
})
|
||||||
|
it('Complete quest : read', () => {
|
||||||
|
cy.CompleteStageWithCommands('read')
|
||||||
|
})
|
||||||
|
it('Complete quest : create', () => {
|
||||||
|
cy.CompleteStageWithCommands('create')
|
||||||
|
})
|
||||||
|
it('Complete quest : copy', () => {
|
||||||
|
cy.CompleteStageWithCommands('copy')
|
||||||
|
})
|
||||||
|
it('Complete quest : move', () => {
|
||||||
|
cy.CompleteStageWithCommands('move')
|
||||||
|
})
|
||||||
|
it('Complete quest : remove', () => {
|
||||||
|
cy.CompleteStageWithCommands('remove')
|
||||||
|
})
|
||||||
|
it('Complete quest : helloworld', () => {
|
||||||
|
cy.CompleteStageWithCommands('helloworld')
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -25,12 +25,17 @@ Cypress.Commands.add('PrepareForGame', () => {
|
|||||||
cy.get('.xterm-screen', { timeout: 10000 })
|
cy.get('.xterm-screen', { timeout: 10000 })
|
||||||
.as('Terminaltextbox')
|
.as('Terminaltextbox')
|
||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
|
cy.checkTaskInit()
|
||||||
cy.CheckTextElement('#reset', '重來', 'Reset').click()
|
cy.CheckTextElement('#reset', '重來', 'Reset').click()
|
||||||
cy.typeInCommand('clear{enter}')
|
cy.checkTaskInit()
|
||||||
|
cy.InitTerminal()
|
||||||
|
})
|
||||||
|
Cypress.Commands.add('InitTerminal', () => {
|
||||||
cy.get('@Terminaltextbox', { timeout: 150000 }).should(
|
cy.get('@Terminaltextbox', { timeout: 150000 }).should(
|
||||||
'contain',
|
'contain',
|
||||||
'commander:~ $'
|
'commander:~ $'
|
||||||
)
|
)
|
||||||
|
cy.log('Check terminal init done')
|
||||||
})
|
})
|
||||||
Cypress.Commands.add('typeInCommand', (command) => {
|
Cypress.Commands.add('typeInCommand', (command) => {
|
||||||
cy.get('.xterm-screen', { timeout: 150000 }).type(command)
|
cy.get('.xterm-screen', { timeout: 150000 }).type(command)
|
||||||
@@ -48,16 +53,26 @@ Cypress.Commands.add('checkHint', (index, total) => {
|
|||||||
.contains(`${index}/${total}`)
|
.contains(`${index}/${total}`)
|
||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
})
|
})
|
||||||
Cypress.Commands.add('waitUntilActive', () => {
|
Cypress.Commands.add('checkTaskInit', () => {
|
||||||
|
cy.get('#tasks').next().children().should('be.visible')
|
||||||
|
})
|
||||||
|
Cypress.Commands.add('waitUntilActive', (last = false) => {
|
||||||
cy.get('input[id="currentStatus"]', { timeout: 1000000 })
|
cy.get('input[id="currentStatus"]', { timeout: 1000000 })
|
||||||
.invoke('val')
|
.invoke('val')
|
||||||
.then((value) => {
|
.then((value) => {
|
||||||
if (value === 'active' || value === 'finished') {
|
if (value === 'active') {
|
||||||
cy.log('story ends')
|
cy.log('story ends')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cy.typeInCommand('{enter}')
|
if (value === 'finished' && last) {
|
||||||
cy.waitUntilActive()
|
cy.log('Quest Finished')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (value === 'pending' && !last) {
|
||||||
|
cy.log(last)
|
||||||
|
cy.typeInCommand('{enter}')
|
||||||
|
cy.waitUntilActive()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
Cypress.Commands.add('checkPending', () => {
|
Cypress.Commands.add('checkPending', () => {
|
||||||
@@ -66,11 +81,34 @@ Cypress.Commands.add('checkPending', () => {
|
|||||||
'pending'
|
'pending'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
Cypress.Commands.add('Complete the Stage (only command)', () => {
|
Cypress.Commands.add('CompleteStageWithCommands', (stagename) => {
|
||||||
cy.log('')
|
cy.visit(`/game/${stagename}`)
|
||||||
|
cy.url().should('include', `/game/${stagename}`)
|
||||||
|
cy.log(`Completing stage :${stagename}`)
|
||||||
|
cy.checkTaskInit()
|
||||||
|
cy.CheckTextElement('#reset', '重來', 'Reset').click()
|
||||||
|
cy.checkTaskInit()
|
||||||
|
cy.InitTerminal()
|
||||||
|
cy.readFile(`../quests/${stagename}/answer.sh`, 'utf-8').as('answers')
|
||||||
|
cy.get('@answers').then((answers) => {
|
||||||
|
const answerarr = answers.split('\n')
|
||||||
|
for (const element of answerarr) {
|
||||||
|
cy.typeInCommand(`${element}{enter}`)
|
||||||
|
if (answerarr.indexOf(element) + 1 !== answerarr.length) {
|
||||||
|
cy.checkPending()
|
||||||
|
cy.waitUntilActive()
|
||||||
|
}
|
||||||
|
if (answerarr.indexOf(element) + 1 === answerarr.length) {
|
||||||
|
cy.waitUntilActive(true)
|
||||||
|
cy.CheckTextElement('#QuestCompleted', '關卡完成!', 'Quest Completed!')
|
||||||
|
cy.get('div[class="modal"]').find('p').should('be.visible')
|
||||||
|
cy.get('#BacktoMap').should('be.visible').and('contain', '回到地圖')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
Cypress.Commands.add('CheckTextElement', (id, chText, enText) => {
|
Cypress.Commands.add('CheckTextElement', (id, chText, enText) => {
|
||||||
cy.get(id).within(($element) => {
|
cy.get(id, { timeout: 50000 }).within(($element) => {
|
||||||
if (Cypress.env('isCHVersion')) {
|
if (Cypress.env('isCHVersion')) {
|
||||||
cy.get($element).should('contain', chText).and('be.visible')
|
cy.get($element).should('contain', chText).and('be.visible')
|
||||||
} else {
|
} else {
|
||||||
@@ -89,3 +127,6 @@ Cypress.Commands.add('CheckPlaceholder', (id, chText, enText) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
Cypress.Commands.add('CheckTreeElement', (element) => {
|
||||||
|
cy.get('#tree').get('a').should('contain', `${element}`).and('be.visible')
|
||||||
|
})
|
||||||
Reference in new issue
Block a user