kopia lustrzana https://dev.funkwhale.audio/funkwhale/funkwhale
feat: Add basic cypress testing
Part-of: <https://dev.funkwhale.audio/funkwhale/funkwhale/-/merge_requests/1795>environments/review-docs-merge-hoc7bt/deployments/18064
rodzic
cfc167fbf3
commit
9aeefca728
|
@ -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:
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Add basic cypress testing
|
|
@ -22,3 +22,6 @@ yarn-error.log*
|
|||
|
||||
# Bundle anayzer
|
||||
stats.html
|
||||
|
||||
cypress/screenshots
|
||||
cypress/videos
|
||||
|
|
|
@ -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',
|
||||
},
|
||||
})
|
|
@ -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')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
|
@ -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')
|
||||
})
|
||||
})
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"username": "demo",
|
||||
"password": "testing1234"
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
|
@ -0,0 +1,9 @@
|
|||
import './commands'
|
||||
|
||||
declare global {
|
||||
namespace Cypress {
|
||||
interface Chainable {
|
||||
login(): Chainable<JQuery<HTMLElement>>
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": ["es5", "dom"],
|
||||
"types": ["cypress", "node"]
|
||||
},
|
||||
"include": ["**/*.ts"],
|
||||
"isolatedModules": false
|
||||
}
|
|
@ -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",
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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, {
|
||||
|
|
|
@ -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
|
||||
|
|
1984
front/yarn.lock
1984
front/yarn.lock
Plik diff jest za duży
Load Diff
Ładowanie…
Reference in New Issue