feat: Add basic cypress testing

Part-of: <https://dev.funkwhale.audio/funkwhale/funkwhale/-/merge_requests/1795>
environments/review-docs-merge-hoc7bt/deployments/18064
Georg Krause 2022-05-12 16:53:43 +02:00 zatwierdzone przez Kasper Seweryn
rodzic cfc167fbf3
commit 9aeefca728
16 zmienionych plików z 1517 dodań i 626 usunięć

Wyświetl plik

@ -313,6 +313,17 @@ build_metadata:
- docker-bake.api.json
- docker-bake.front.json
test_integration:
interruptible: true
stage: test
image: cypress/base:16.14.2
before_script:
- cd front
- yarn install
script:
- yarn run cypress run
build_api_schema:
stage: build
needs:

Wyświetl plik

@ -0,0 +1 @@
Add basic cypress testing

3
front/.gitignore vendored
Wyświetl plik

@ -22,3 +22,6 @@ yarn-error.log*
# Bundle anayzer
stats.html
cypress/screenshots
cypress/videos

Wyświetl plik

@ -0,0 +1,13 @@
import { defineConfig } from 'cypress'
export default defineConfig({
chromeWebSecurity: false,
e2e: {
// We've imported your old cypress plugins here.
// You may want to clean this up later by importing these.
setupNodeEvents(on, config) {
return require('./cypress/plugins/index.js')(on, config)
},
baseUrl: 'https://demo.funkwhale.audio',
},
})

Wyświetl plik

@ -0,0 +1,31 @@
describe('Favorites', () => {
it('can be done from album list view', () => {
cy.login()
cy.visit('/')
cy.wait(4000)
cy.get('.item.collapse-button-wrapper').click()
cy.contains('Albums').click()
cy.get('.component-album-card').first().within(() => {
cy.get('a').first().click()
})
cy.get('.track-row.row').first().trigger('hover').within(() => {
cy.get('.favorite-icon').then(($favButton) => {
$favButton.click()
// In case everything worked the favorite button should be pink
cy.wrap($favButton).should('have.class', 'pink')
})
cy.get('.favorite-icon.pink').then(($unfavButton) => {
$unfavButton.click()
// In case everything worked the favorite button shouldn't be pink
// anymore
cy.wrap($unfavButton).should('not.have.class', 'pink')
})
})
})
})

Wyświetl plik

@ -0,0 +1,19 @@
describe('The login', () => {
it('is working with UI', () => {
cy.fixture('testuser.json').then((user) => {
cy.visit('/login')
cy.get('input[name=username]').type(user['username'])
cy.get('input[name=password]').type(`${user['password']}{enter}`)
})
cy.url().should('include', '/library')
cy.getCookie('sessionid').should('exist')
})
it('is working without UI', () => {
cy.login()
cy.visit('/library')
cy.get('.ui.avatar.circular.label').should('exist')
cy.getCookie('sessionid').should('exist')
})
})

Wyświetl plik

@ -0,0 +1,4 @@
{
"username": "demo",
"password": "testing1234"
}

Wyświetl plik

@ -0,0 +1,22 @@
/// <reference types="cypress" />
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
// You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************
// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)
/**
* @type {Cypress.PluginConfig}
*/
// eslint-disable-next-line no-unused-vars
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
}

Wyświetl plik

@ -0,0 +1,27 @@
// Currently we cannot login purely programmatically, so we need to use the
// graphical login until the vue3 branch is merged
Cypress.Commands.add('login', () => {
cy.fixture('testuser.json').then((user) => {
var username = user["username"]
var password = user["password"]
cy.visit('/login')
cy.wait(1000)
cy.getCookie('csrftoken').then(($cookie) => {
const csrfToken = $cookie?.value
cy.request({
method: 'POST',
url: '/api/v1/users/login',
form: true,
headers: {
'X-CSRFTOKEN': csrfToken,
Referer: Cypress.config().baseUrl + '/login',
},
body: {
username,
password
},
})
})
})
})

Wyświetl plik

@ -0,0 +1,9 @@
import './commands'
declare global {
namespace Cypress {
interface Chainable {
login(): Chainable<JQuery<HTMLElement>>
}
}
}

Wyświetl plik

@ -0,0 +1,9 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["es5", "dom"],
"types": ["cypress", "node"]
},
"include": ["**/*.ts"],
"isolatedModules": false
}

Wyświetl plik

@ -78,6 +78,7 @@
"@vue/test-utils": "2.2.7",
"@vue/tsconfig": "0.1.3",
"axios-mock-adapter": "1.21.4",
"cypress": "12.13.0",
"eslint": "8.30.0",
"eslint-config-standard": "17.0.0",
"eslint-plugin-html": "7.1.0",
@ -88,6 +89,7 @@
"eslint-plugin-vue": "9.8.0",
"jsdom": "20.0.3",
"jsonc-eslint-parser": "2.1.0",
"p-limit": "4.0.0",
"rollup-plugin-visualizer": "5.9.0",
"sass": "1.57.1",
"sinon": "15.0.2",

Wyświetl plik

@ -25,5 +25,5 @@ const defaultAvatarStyle = computed(() => ({ backgroundColor: `#${actorColor.val
v-else
:style="defaultAvatarStyle"
class="ui avatar circular label"
>{{ actor.preferred_username[0] }}</span>
>{{ actor.preferred_username?.[0] || "" }}</span>
</template>

Wyświetl plik

@ -7,7 +7,7 @@ import { CLIENT_RADIOS } from '~/utils/clientRadios'
export const install: InitModule = ({ store }) => {
watch(() => store.state.instance.instanceUrl, () => {
const url = store.getters['instance/absoluteUrl']('api/v1/activity')
const url = store.getters['instance/absoluteUrl']('/api/v1/activity')
.replace(/^http/, 'ws')
const { data, status, open, close } = useWebSocket(url, {

Wyświetl plik

@ -248,12 +248,12 @@ const store: Module<State, RootState> = {
const response = await axios.get('instance/settings/')
.catch(err => logger.error('Error while fetching settings', err.response.data))
if (!response) return
if (!Array.isArray(response?.data)) return
logger.info('Successfully fetched instance settings')
type SettingsSection = { section: string, name: string }
const sections = response.data.reduce((map: Record<string, Record<string, SettingsSection>>, entry: SettingsSection) => {
const sections = response?.data.reduce((map: Record<string, Record<string, SettingsSection>>, entry: SettingsSection) => {
map[entry.section] ??= {}
map[entry.section][entry.name] = entry
return map

Plik diff jest za duży Load Diff