mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2024-12-20 19:06:06 +01:00
Add LazyBookCard tests
This commit is contained in:
parent
8cc3bfa95e
commit
b244cc8d41
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div ref="card" :id="`book-card-${index}`" :style="{ minWidth: width + 'px', maxWidth: width + 'px', height: height + 'px' }" class="rounded-sm z-10 bg-primary cursor-pointer box-shadow-book" @mousedown.prevent @mouseup.prevent @mousemove.prevent @mouseover="mouseover" @mouseleave="mouseleave" @click="clickCard">
|
<div ref="card" :id="`book-card-${index}`" :style="{ minWidth: width + 'px', maxWidth: width + 'px', height: height + 'px' }" class="absolute rounded-sm z-10 bg-primary cursor-pointer box-shadow-book" @mousedown.prevent @mouseup.prevent @mousemove.prevent @mouseover="mouseover" @mouseleave="mouseleave" @click="clickCard">
|
||||||
<!-- When cover image does not fill -->
|
<!-- When cover image does not fill -->
|
||||||
<div cy-id="coverBg" v-show="showCoverBg" class="absolute top-0 left-0 w-full h-full overflow-hidden rounded-sm bg-primary">
|
<div cy-id="coverBg" v-show="showCoverBg" class="absolute top-0 left-0 w-full h-full overflow-hidden rounded-sm bg-primary">
|
||||||
<div class="absolute cover-bg" ref="coverBg" />
|
<div class="absolute cover-bg" ref="coverBg" />
|
||||||
@ -345,7 +345,7 @@ export default {
|
|||||||
const useEBookProgress = this.useEBookProgress
|
const useEBookProgress = this.useEBookProgress
|
||||||
this.libraryItemIdsInSeries.forEach((lid) => {
|
this.libraryItemIdsInSeries.forEach((lid) => {
|
||||||
const progress = this.store.getters['user/getUserMediaProgress'](lid)
|
const progress = this.store.getters['user/getUserMediaProgress'](lid)
|
||||||
if (progress && progress.progress) progressPercent += useEBookProgress ? progress.ebookProgress || 0 : progress.progress || 0
|
if (progress) progressPercent += progress.isFinished ? 1 : useEBookProgress ? progress.ebookProgress || 0 : progress.progress || 0
|
||||||
})
|
})
|
||||||
return progressPercent / this.libraryItemIdsInSeries.length
|
return progressPercent / this.libraryItemIdsInSeries.length
|
||||||
},
|
},
|
||||||
|
BIN
client/cypress/fixtures/images/cover1.jpg
Normal file
BIN
client/cypress/fixtures/images/cover1.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 184 KiB |
BIN
client/cypress/fixtures/images/cover2.jpg
Normal file
BIN
client/cypress/fixtures/images/cover2.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 315 KiB |
342
client/cypress/tests/components/cards/LazyBookCard.cy.js
Normal file
342
client/cypress/tests/components/cards/LazyBookCard.cy.js
Normal file
@ -0,0 +1,342 @@
|
|||||||
|
import LazyBookCard from '@/components/cards/LazyBookCard'
|
||||||
|
import Tooltip from '@/components/ui/Tooltip.vue'
|
||||||
|
import ExplicitIndicator from '@/components/widgets/ExplicitIndicator.vue'
|
||||||
|
import LoadingSpinner from '@/components/widgets/LoadingSpinner.vue'
|
||||||
|
import { Constants } from '@/plugins/constants'
|
||||||
|
|
||||||
|
function createMountOptions() {
|
||||||
|
const book = {
|
||||||
|
id: '1',
|
||||||
|
ino: '281474976785140',
|
||||||
|
libraryId: 'library-123',
|
||||||
|
folderId: 'folder-123',
|
||||||
|
path: '/path/to/book',
|
||||||
|
relPath: 'book',
|
||||||
|
isFile: false,
|
||||||
|
mtimeMs: 1689017292016,
|
||||||
|
ctimeMs: 1689017292016,
|
||||||
|
birthtimeMs: 1689017281555,
|
||||||
|
addedAt: 1700154928492,
|
||||||
|
updatedAt: 1713300533345,
|
||||||
|
isMissing: false,
|
||||||
|
isInvalid: false,
|
||||||
|
mediaType: 'book',
|
||||||
|
media: {
|
||||||
|
id: 'book1',
|
||||||
|
metadata: {
|
||||||
|
title: 'The Fellowship of the Ring',
|
||||||
|
titleIgnorePrefix: 'Fellowship of the Ring',
|
||||||
|
subtitle: 'LOTR, Book 1',
|
||||||
|
authorName: 'J. R. R. Tolkien',
|
||||||
|
authorNameLF: 'Tolkien, J. R. R.',
|
||||||
|
narratorName: 'Andy Sirkis',
|
||||||
|
genres: ['Science Fiction & Fantasy'],
|
||||||
|
publishedYear: '2017',
|
||||||
|
publishedDate: null,
|
||||||
|
publisher: 'Book Publisher',
|
||||||
|
description: 'Book Description',
|
||||||
|
isbn: null,
|
||||||
|
asin: 'B075LXMLNV',
|
||||||
|
language: 'English',
|
||||||
|
explicit: false,
|
||||||
|
abridged: false
|
||||||
|
},
|
||||||
|
coverPath: null,
|
||||||
|
tags: ['Fantasy', 'Adventure'],
|
||||||
|
numTracks: 1,
|
||||||
|
numAudioFiles: 1,
|
||||||
|
numChapters: 31,
|
||||||
|
duration: 64410,
|
||||||
|
size: 511206878
|
||||||
|
},
|
||||||
|
numFiles: 4,
|
||||||
|
size: 511279587
|
||||||
|
}
|
||||||
|
|
||||||
|
const propsData = {
|
||||||
|
index: 0,
|
||||||
|
bookMount: book,
|
||||||
|
bookCoverAspectRatio: 1,
|
||||||
|
bookshelfView: Constants.BookshelfView.DETAIL,
|
||||||
|
continueListeningShelf: false,
|
||||||
|
filterBy: null,
|
||||||
|
width: 192,
|
||||||
|
height: 192,
|
||||||
|
sortingIgnorePrefix: false,
|
||||||
|
orderBy: null
|
||||||
|
}
|
||||||
|
|
||||||
|
const stubs = {
|
||||||
|
'ui-tooltip': Tooltip,
|
||||||
|
'widgets-explicit-indicator': ExplicitIndicator,
|
||||||
|
'widgets-loading-spinner': LoadingSpinner
|
||||||
|
}
|
||||||
|
|
||||||
|
const mocks = {
|
||||||
|
$config: {
|
||||||
|
routerBasePath: 'https://my.server.com'
|
||||||
|
},
|
||||||
|
$store: {
|
||||||
|
commit: () => {},
|
||||||
|
getters: {
|
||||||
|
'user/getUserCanUpdate': true,
|
||||||
|
'user/getUserCanDelete': true,
|
||||||
|
'user/getUserCanDownload': true,
|
||||||
|
'user/getIsAdminOrUp': true,
|
||||||
|
'user/getUserMediaProgress': (id) => null,
|
||||||
|
'libraries/getLibraryProvider': () => 'audible.us',
|
||||||
|
'globals/getLibraryItemCoverSrc': () => 'https://my.server.com/book_placeholder.jpg',
|
||||||
|
getLibraryItemsStreaming: () => null,
|
||||||
|
getIsMediaQueued: () => false,
|
||||||
|
getIsStreamingFromDifferentLibrary: () => false
|
||||||
|
},
|
||||||
|
state: {
|
||||||
|
libraries: {
|
||||||
|
currentLibraryId: 'library-123'
|
||||||
|
},
|
||||||
|
processingBatch: false,
|
||||||
|
serverSettings: {
|
||||||
|
dateFormat: 'MM/dd/yyyy'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { propsData, stubs, mocks }
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('LazyBookCard', () => {
|
||||||
|
let mountOptions = null
|
||||||
|
beforeEach(() => {
|
||||||
|
mountOptions = createMountOptions()
|
||||||
|
// cy.intercept(
|
||||||
|
// 'https://my.server.com/**/*',
|
||||||
|
// { middleware: true },
|
||||||
|
// (req) => {
|
||||||
|
// req.on('before:response', (res) => {
|
||||||
|
// // force all API responses to not be cached
|
||||||
|
// res.headers['cache-control'] = 'no-store'
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// )
|
||||||
|
})
|
||||||
|
|
||||||
|
before(() => {
|
||||||
|
// Put placeholder image is in the browser cache
|
||||||
|
mountOptions = createMountOptions()
|
||||||
|
cy.intercept('https://my.server.com/book_placeholder.jpg', { fixture: 'images/book_placeholder.jpg' }).as('bookCover')
|
||||||
|
cy.mount(LazyBookCard, mountOptions)
|
||||||
|
cy.wait('@bookCover')
|
||||||
|
|
||||||
|
// Put cover1 (aspect ratio 1.6) image in the browser cache
|
||||||
|
mountOptions = createMountOptions()
|
||||||
|
mountOptions.mocks.$store.getters['globals/getLibraryItemCoverSrc'] = () => 'https://my.server.com/cover1.jpg'
|
||||||
|
cy.intercept('https://my.server.com/cover1.jpg', { fixture: 'images/cover1.jpg' }).as('bookCover1')
|
||||||
|
cy.mount(LazyBookCard, mountOptions)
|
||||||
|
cy.wait('@bookCover1')
|
||||||
|
|
||||||
|
// Put cover2 (aspect ratio 1) image in the browser cache
|
||||||
|
mountOptions = createMountOptions()
|
||||||
|
mountOptions.mocks.$store.getters['globals/getLibraryItemCoverSrc'] = () => 'https://my.server.com/cover2.jpg'
|
||||||
|
cy.intercept('https://my.server.com/cover2.jpg', { fixture: 'images/cover2.jpg' }).as('bookCover2')
|
||||||
|
cy.mount(LazyBookCard, mountOptions)
|
||||||
|
cy.wait('@bookCover2')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders the component correctly', () => {
|
||||||
|
cy.mount(LazyBookCard, mountOptions)
|
||||||
|
|
||||||
|
cy.get('&titleImageNotReady').should('be.hidden')
|
||||||
|
cy.get('&coverImage').should('have.css', 'opacity', '1')
|
||||||
|
cy.get('&coverBg').should('be.hidden')
|
||||||
|
cy.get('&overlay').should('be.hidden')
|
||||||
|
cy.get('&detailBottom').should('be.visible')
|
||||||
|
cy.get('&title').should('have.text', 'The Fellowship of the Ring')
|
||||||
|
cy.get('&explicitIndicator').should('not.exist')
|
||||||
|
cy.get('&line2').should('have.text', 'J. R. R. Tolkien')
|
||||||
|
cy.get('&line3').should('not.exist')
|
||||||
|
cy.get('seriesSequenceList').should('not.exist')
|
||||||
|
cy.get('&booksInSeries').should('not.exist')
|
||||||
|
cy.get('&placeholderTitle').should('be.visible')
|
||||||
|
cy.get('&placeholderTitleText').should('have.text', 'The Fellowship of the Ring')
|
||||||
|
cy.get('&placeholderAuthor').should('be.visible')
|
||||||
|
cy.get('&placeholderAuthorText').should('have.text', 'J. R. R. Tolkien')
|
||||||
|
cy.get('&progressBar').should('be.hidden')
|
||||||
|
cy.get('&finishedProgressBar').should('not.exist')
|
||||||
|
cy.get('&loadingSpinner').should('not.exist')
|
||||||
|
cy.get('&seriesNameOverlay').should('not.exist')
|
||||||
|
cy.get('&errorTooltip').should('not.exist')
|
||||||
|
cy.get('&rssFeed').should('not.exist')
|
||||||
|
cy.get('&seriesSequence').should('not.exist')
|
||||||
|
cy.get('&podcastEpisdeNumber').should('not.exist')
|
||||||
|
|
||||||
|
// this should actually fail, since the height does not cover
|
||||||
|
// the detailBottom element, currently rendered outside the card's area,
|
||||||
|
// and requires complex layout calculations outside of the component.
|
||||||
|
// todo: fix the component to render the detailBottom element inside the card's area
|
||||||
|
cy.get('#book-card-0').should(($el) => {
|
||||||
|
const width = $el.width()
|
||||||
|
const height = $el.height()
|
||||||
|
expect(width).to.be.closeTo(mountOptions.propsData.width, 0.01)
|
||||||
|
expect(height).to.be.closeTo(mountOptions.propsData.height, 0.01)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows overlay on mouseover', () => {
|
||||||
|
cy.mount(LazyBookCard, mountOptions)
|
||||||
|
cy.get('#book-card-0').trigger('mouseover')
|
||||||
|
|
||||||
|
cy.get('&titleImageNotReady').should('be.hidden')
|
||||||
|
cy.get('&overlay').should('be.visible')
|
||||||
|
cy.get('&playButton').should('be.visible')
|
||||||
|
cy.get('&readButton').should('be.hidden')
|
||||||
|
cy.get('&editButton').should('be.visible')
|
||||||
|
cy.get('&selectedRadioButton').should('be.visible').and('have.text', 'radio_button_unchecked')
|
||||||
|
cy.get('&moreButton').should('be.visible')
|
||||||
|
cy.get('&ebookFormat').should('not.exist')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('routes to item page when clicked', () => {
|
||||||
|
mountOptions.mocks.$router = { push: cy.stub().as('routerPush') }
|
||||||
|
cy.mount(LazyBookCard, mountOptions)
|
||||||
|
cy.get('#book-card-0').click()
|
||||||
|
|
||||||
|
cy.get('@routerPush').should('have.been.calledOnceWithExactly', '/item/1')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows titleImageNotReady and sets opacity 0 on coverImage when image not ready', () => {
|
||||||
|
cy.mount(LazyBookCard, mountOptions)
|
||||||
|
|
||||||
|
cy.get('&titleImageNotReady').should('be.visible')
|
||||||
|
cy.get('&coverImage').should('have.css', 'opacity', '0')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows coverBg when coverImage has different aspect ratio', () => {
|
||||||
|
mountOptions.mocks.$store.getters['globals/getLibraryItemCoverSrc'] = () => 'https://my.server.com/cover1.jpg'
|
||||||
|
cy.mount(LazyBookCard, mountOptions)
|
||||||
|
|
||||||
|
cy.get('&coverBg').should('be.visible')
|
||||||
|
cy.get('&coverImage').should('have.class', 'object-contain')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('hides coverBg when coverImage has same aspect ratio', () => {
|
||||||
|
mountOptions.mocks.$store.getters['globals/getLibraryItemCoverSrc'] = () => 'https://my.server.com/cover2.jpg'
|
||||||
|
cy.mount(LazyBookCard, mountOptions)
|
||||||
|
|
||||||
|
cy.get('&coverBg').should('be.hidden')
|
||||||
|
cy.get('&coverImage').should('have.class', 'object-fill')
|
||||||
|
})
|
||||||
|
|
||||||
|
// The logic for displaying placeholder title and author seems incorrect.
|
||||||
|
// It is currently based on existence of coverPath, but should be based weater the actual cover image is placeholder or not.
|
||||||
|
// todo: fix the logic to display placeholder title and author based on the actual cover image.
|
||||||
|
it('hides placeholderTitle and placeholderAuthor when book has cover', () => {
|
||||||
|
mountOptions.mocks.$store.getters['globals/getLibraryItemCoverSrc'] = () => 'https://my.server.com/cover1.jpg'
|
||||||
|
mountOptions.propsData.bookMount.media.coverPath = 'cover1.jpg'
|
||||||
|
cy.mount(LazyBookCard, mountOptions)
|
||||||
|
|
||||||
|
cy.get('&placeholderTitle').should('not.exist')
|
||||||
|
cy.get('&placeholderAuthor').should('not.exist')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('hides detailBottom when bookShelfView is STANDARD', () => {
|
||||||
|
mountOptions.propsData.bookshelfView = Constants.BookshelfView.STANDARD
|
||||||
|
cy.mount(LazyBookCard, mountOptions)
|
||||||
|
|
||||||
|
cy.get('&detailBottom').should('not.exist')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows explicit indicator when book is explicit', () => {
|
||||||
|
mountOptions.propsData.bookMount.media.metadata.explicit = true
|
||||||
|
cy.mount(LazyBookCard, mountOptions)
|
||||||
|
|
||||||
|
cy.get('&explicitIndicator').should('be.visible')
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('when collapsedSeries is present', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mountOptions.propsData.bookMount.collapsedSeries = {
|
||||||
|
id: 'series-123',
|
||||||
|
name: 'The Lord of the Rings',
|
||||||
|
nameIgnorePrefix: 'Lord of the Rings',
|
||||||
|
numBooks: 3,
|
||||||
|
libraryItemIds: ['1', '2', '3']
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows the collpased series', () => {
|
||||||
|
cy.mount(LazyBookCard, mountOptions)
|
||||||
|
|
||||||
|
cy.get('&seriesSequenceList').should('not.exist')
|
||||||
|
cy.get('&booksInSeries').should('be.visible').and('have.text', '3')
|
||||||
|
cy.get('&title').should('be.visible').and('have.text', 'The Lord of the Rings')
|
||||||
|
cy.get('&line2').should('be.visible').and('have.text', '\u00a0')
|
||||||
|
cy.get('&progressBar').should('be.hidden')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows the seriesNameOverlay on mouseover', () => {
|
||||||
|
mountOptions.propsData.bookMount.media.metadata.series = {
|
||||||
|
id: 'series-456',
|
||||||
|
name: 'Middle Earth Chronicles',
|
||||||
|
sequence: 1
|
||||||
|
}
|
||||||
|
cy.mount(LazyBookCard, mountOptions)
|
||||||
|
cy.get('#book-card-0').trigger('mouseover')
|
||||||
|
|
||||||
|
cy.get('&seriesNameOverlay').should('be.visible').and('have.text', 'Middle Earth Chronicles')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows the seriesSequenceList when collapsed series has a sequence list', () => {
|
||||||
|
mountOptions.propsData.bookMount.collapsedSeries.seriesSequenceList = '1-3'
|
||||||
|
cy.mount(LazyBookCard, mountOptions)
|
||||||
|
|
||||||
|
cy.get('&seriesSequenceList').should('be.visible').and('have.text', '#1-3')
|
||||||
|
cy.get('&booksInSeries').should('not.exist')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('routes to the series page when clicked', () => {
|
||||||
|
mountOptions.mocks.$router = { push: cy.stub().as('routerPush') }
|
||||||
|
cy.mount(LazyBookCard, mountOptions)
|
||||||
|
cy.get('#book-card-0').click()
|
||||||
|
|
||||||
|
cy.get('@routerPush').should('have.been.calledOnceWithExactly', '/library/library-123/series/series-123')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows the series progress bar when series has progress', () => {
|
||||||
|
mountOptions.mocks.$store.getters['user/getUserMediaProgress'] = (id) => {
|
||||||
|
switch (id) {
|
||||||
|
case '1':
|
||||||
|
return { isFinished: true }
|
||||||
|
case '2':
|
||||||
|
return { progress: 0.5 }
|
||||||
|
default:
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cy.mount(LazyBookCard, mountOptions)
|
||||||
|
|
||||||
|
cy.get('&progressBar')
|
||||||
|
.should('be.visible')
|
||||||
|
.and('have.class', 'bg-yellow-400')
|
||||||
|
.and(($el) => {
|
||||||
|
const width = $el.width()
|
||||||
|
expect(width).to.be.closeTo(((1 + 0.5) / 3) * mountOptions.propsData.width, 0.01)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows full green progress bar when all books are finished', () => {
|
||||||
|
mountOptions.mocks.$store.getters['user/getUserMediaProgress'] = (id) => {
|
||||||
|
return { isFinished: true }
|
||||||
|
}
|
||||||
|
cy.mount(LazyBookCard, mountOptions)
|
||||||
|
|
||||||
|
cy.get('&progressBar')
|
||||||
|
.should('be.visible')
|
||||||
|
.and('have.class', 'bg-success')
|
||||||
|
.and(($el) => {
|
||||||
|
const width = $el.width()
|
||||||
|
expect(width).to.be.equal(mountOptions.propsData.width)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
Loading…
Reference in New Issue
Block a user