mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-07-10 03:11:34 +00:00
feat: unified package
This commit is contained in:
parent
f850db23fe
commit
0f42a4d580
335 changed files with 18102 additions and 19926 deletions
196
cypress/tests/components/cards/AuthorCard.cy.js
Normal file
196
cypress/tests/components/cards/AuthorCard.cy.js
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
// Import the necessary dependencies
|
||||
import AuthorCard from '@/components/cards/AuthorCard.vue'
|
||||
import AuthorImage from '@/components/covers/AuthorImage.vue'
|
||||
import Tooltip from '@/components/ui/Tooltip.vue'
|
||||
import LoadingSpinner from '@/components/widgets/LoadingSpinner.vue'
|
||||
|
||||
describe('AuthorCard', () => {
|
||||
const authorMount = {
|
||||
id: 1,
|
||||
name: 'John Doe',
|
||||
numBooks: 5
|
||||
}
|
||||
|
||||
const propsData = {
|
||||
authorMount,
|
||||
nameBelow: false
|
||||
}
|
||||
|
||||
const mocks = {
|
||||
$strings: {
|
||||
LabelBooks: 'Books',
|
||||
ButtonQuickMatch: 'Quick Match'
|
||||
},
|
||||
$store: {
|
||||
getters: {
|
||||
'user/getUserCanUpdate': true,
|
||||
'libraries/getLibraryProvider': () => 'audible.us',
|
||||
'user/getSizeMultiplier': 1
|
||||
},
|
||||
state: {
|
||||
libraries: {
|
||||
currentLibraryId: 'library-123'
|
||||
}
|
||||
}
|
||||
},
|
||||
$eventBus: {
|
||||
$on: () => {},
|
||||
$off: () => {}
|
||||
}
|
||||
}
|
||||
|
||||
const stubs = {
|
||||
'covers-author-image': AuthorImage,
|
||||
'ui-tooltip': Tooltip,
|
||||
'widgets-loading-spinner': LoadingSpinner
|
||||
}
|
||||
|
||||
const mountOptions = { propsData, mocks, stubs }
|
||||
|
||||
it('renders the component', () => {
|
||||
cy.mount(AuthorCard, mountOptions)
|
||||
|
||||
cy.get('&textInline').should('be.visible')
|
||||
cy.get('&match').should('be.hidden')
|
||||
cy.get('&edit').should('be.hidden')
|
||||
cy.get('&nameBelow').should('be.hidden')
|
||||
cy.get('&card').should(($el) => {
|
||||
const width = $el.width()
|
||||
const height = $el.height()
|
||||
const defaultHeight = 192
|
||||
const defaultWidth = defaultHeight * 0.8
|
||||
expect(width).to.be.closeTo(defaultWidth, 0.01)
|
||||
expect(height).to.be.closeTo(defaultHeight, 0.01)
|
||||
})
|
||||
})
|
||||
|
||||
it('renders the component with the author name below', () => {
|
||||
const updatedPropsData = { ...propsData, nameBelow: true }
|
||||
cy.mount(AuthorCard, { ...mountOptions, propsData: updatedPropsData })
|
||||
|
||||
cy.get('&textInline').should('be.hidden')
|
||||
cy.get('&match').should('be.hidden')
|
||||
cy.get('&edit').should('be.hidden')
|
||||
let nameBelowHeight
|
||||
cy.get('&nameBelow')
|
||||
.should('be.visible')
|
||||
.and('have.text', 'John Doe')
|
||||
.and(($el) => {
|
||||
const height = $el.height()
|
||||
const width = $el.width()
|
||||
const sizeMultiplier = 1
|
||||
const defaultFontSize = 16
|
||||
const defaultLineHeight = 1.5
|
||||
const fontSizeMultiplier = 0.75
|
||||
const px2 = 16
|
||||
const defaultHeight = 192
|
||||
const defaultWidth = defaultHeight * 0.8
|
||||
expect(height).to.be.closeTo(defaultFontSize * fontSizeMultiplier * sizeMultiplier * defaultLineHeight, 0.01)
|
||||
nameBelowHeight = height
|
||||
expect(width).to.be.closeTo(defaultWidth - px2, 0.01)
|
||||
})
|
||||
cy.get('&card').should(($el) => {
|
||||
const width = $el.width()
|
||||
const height = $el.height()
|
||||
const py1 = 8
|
||||
const defaultHeight = 192
|
||||
const defaultWidth = defaultHeight * 0.8
|
||||
expect(width).to.be.closeTo(defaultWidth, 0.01)
|
||||
expect(height).to.be.closeTo(defaultHeight + nameBelowHeight + py1, 0.01)
|
||||
})
|
||||
})
|
||||
|
||||
it('renders quick-match and edit buttons on mouse hover', () => {
|
||||
cy.mount(AuthorCard, mountOptions)
|
||||
|
||||
// before mouseover
|
||||
cy.get('&match').should('be.hidden')
|
||||
cy.get('&edit').should('be.hidden')
|
||||
// after mouseover
|
||||
cy.get('&card').trigger('mouseover')
|
||||
cy.get('&match').should('be.visible')
|
||||
cy.get('&edit').should('be.visible')
|
||||
// after mouseleave
|
||||
cy.get('&card').trigger('mouseleave')
|
||||
cy.get('&match').should('be.hidden')
|
||||
cy.get('&edit').should('be.hidden')
|
||||
})
|
||||
|
||||
it('renders the component with spinner while searching', () => {
|
||||
const data = () => {
|
||||
return { searching: true, isHovering: false }
|
||||
}
|
||||
cy.mount(AuthorCard, { ...mountOptions, data })
|
||||
|
||||
cy.get('&textInline').should('be.hidden')
|
||||
cy.get('&match').should('be.hidden')
|
||||
cy.get('&edit').should('be.hidden')
|
||||
cy.get('&spinner').should('be.visible')
|
||||
})
|
||||
|
||||
it('toasts after quick match with no updates', () => {
|
||||
const updatedMocks = {
|
||||
...mocks,
|
||||
$axios: {
|
||||
$post: cy.stub().resolves({ updated: false, author: { name: 'John Doe' } })
|
||||
},
|
||||
$toast: {
|
||||
success: cy.spy().as('success'),
|
||||
error: cy.spy().as('error'),
|
||||
info: cy.spy().as('info')
|
||||
}
|
||||
}
|
||||
cy.mount(AuthorCard, { ...mountOptions, mocks: updatedMocks })
|
||||
cy.get('&card').trigger('mouseover')
|
||||
cy.get('&match').click()
|
||||
|
||||
cy.get('&spinner').should('be.hidden')
|
||||
cy.get('@success').should('not.have.been.called')
|
||||
cy.get('@error').should('not.have.been.called')
|
||||
cy.get('@info').should('have.been.called')
|
||||
})
|
||||
|
||||
it('toasts after quick match with updates and no image', () => {
|
||||
const updatedMocks = {
|
||||
...mocks,
|
||||
$axios: {
|
||||
$post: cy.stub().resolves({ updated: true, author: { name: 'John Doe' } })
|
||||
},
|
||||
$toast: {
|
||||
success: cy.stub().as('success'),
|
||||
error: cy.spy().as('error'),
|
||||
info: cy.spy().as('info')
|
||||
}
|
||||
}
|
||||
cy.mount(AuthorCard, { ...mountOptions, mocks: updatedMocks })
|
||||
cy.get('&card').trigger('mouseover')
|
||||
cy.get('&match').click()
|
||||
|
||||
cy.get('&spinner').should('be.hidden')
|
||||
cy.get('@success').should('have.been.calledOnceWithExactly', 'Author John Doe was updated (no image found)')
|
||||
cy.get('@error').should('not.have.been.called')
|
||||
cy.get('@info').should('not.have.been.called')
|
||||
})
|
||||
|
||||
it('toasts after quick match with updates including image', () => {
|
||||
const updatedMocks = {
|
||||
...mocks,
|
||||
$axios: {
|
||||
$post: cy.stub().resolves({ updated: true, author: { name: 'John Doe', imagePath: 'path/to/image' } })
|
||||
},
|
||||
$toast: {
|
||||
success: cy.stub().as('success'),
|
||||
error: cy.spy().as('error'),
|
||||
info: cy.spy().as('info')
|
||||
}
|
||||
}
|
||||
cy.mount(AuthorCard, { ...mountOptions, mocks: updatedMocks })
|
||||
cy.get('&card').trigger('mouseover')
|
||||
cy.get('&match').click()
|
||||
|
||||
cy.get('&spinner').should('be.hidden')
|
||||
cy.get('@success').should('have.been.calledOnceWithExactly', 'Author John Doe was updated')
|
||||
cy.get('@error').should('not.have.been.called')
|
||||
cy.get('@info').should('not.have.been.called')
|
||||
})
|
||||
})
|
||||
85
cypress/tests/components/cards/ItemSlider.cy.js
Normal file
85
cypress/tests/components/cards/ItemSlider.cy.js
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
import ItemSlider from '@/components/widgets/ItemSlider.vue'
|
||||
import NarratorCard from '@/components/cards/NarratorCard.vue'
|
||||
import AuthorCard from '@/components/cards/AuthorCard.vue'
|
||||
|
||||
function createMountOptions(shelftype) {
|
||||
const items = {
|
||||
narrators: [
|
||||
{ name: 'John Doe', numBooks: 5 },
|
||||
{ name: 'Jane Doe', numBooks: 3 },
|
||||
{ name: 'Jack Doe', numBooks: 1 },
|
||||
{ name: 'Jill Doe', numBooks: 7 }
|
||||
],
|
||||
authors: [
|
||||
{ id: 1, name: 'John Doe', numBooks: 5 },
|
||||
{ id: 2, name: 'Jane Doe', numBooks: 3 },
|
||||
{ id: 3, name: 'Jack Doe', numBooks: 1 },
|
||||
{ id: 4, name: 'Jill Doe', numBooks: 7 }
|
||||
]
|
||||
}
|
||||
const propsData = {
|
||||
items: items[shelftype],
|
||||
shelfId: 'shelf-123',
|
||||
type: shelftype
|
||||
}
|
||||
const stubs = {
|
||||
'cards-narrator-card': NarratorCard,
|
||||
'cards-author-card': AuthorCard
|
||||
}
|
||||
const mocks = {
|
||||
$store: {
|
||||
getters: {
|
||||
'user/getUserCanUpdate': true,
|
||||
'user/getSizeMultiplier': 1,
|
||||
'globals/getIsBatchSelectingMediaItems': false
|
||||
},
|
||||
state: {
|
||||
libraries: {
|
||||
currentLibraryId: 'library-123'
|
||||
}
|
||||
}
|
||||
},
|
||||
$eventBus: {
|
||||
$on: () => {},
|
||||
$off: () => {}
|
||||
}
|
||||
}
|
||||
const slots = {
|
||||
default: `<p class="font-semibold text-gray-100">${shelftype}</p>`
|
||||
}
|
||||
|
||||
return { propsData, stubs, mocks, slots }
|
||||
}
|
||||
|
||||
describe('ItemSlider', () => {
|
||||
let mountOptions = null
|
||||
|
||||
beforeEach(() => {})
|
||||
|
||||
it('renders a narrators slider', () => {
|
||||
mountOptions = createMountOptions('narrators')
|
||||
cy.mount(ItemSlider, mountOptions)
|
||||
|
||||
cy.get('&item').should('have.length', 4)
|
||||
cy.get('&leftScrollButton').should('be.visible').and('not.have.class', 'text-gray-300')
|
||||
cy.get('&rightScrollButton').should('be.visible').and('have.class', 'text-gray-300')
|
||||
})
|
||||
|
||||
it('renders an authors slider', () => {
|
||||
mountOptions = createMountOptions('authors')
|
||||
cy.mount(ItemSlider, mountOptions)
|
||||
|
||||
cy.get('&item').should('have.length', 4)
|
||||
cy.get('&leftScrollButton').should('be.visible').and('not.have.class', 'text-gray-300')
|
||||
cy.get('&rightScrollButton').should('be.visible').and('have.class', 'text-gray-300')
|
||||
})
|
||||
|
||||
it('hides the scroll button when all items are visible', () => {
|
||||
mountOptions = createMountOptions('narrators')
|
||||
mountOptions.propsData.items = mountOptions.propsData.items.slice(0, 2)
|
||||
cy.mount(ItemSlider, mountOptions)
|
||||
|
||||
cy.get('&leftScrollButton').should('not.exist')
|
||||
cy.get('&rightScrollButton').should('not.exist')
|
||||
})
|
||||
})
|
||||
324
cypress/tests/components/cards/LazyBookCard.cy.js
Normal file
324
cypress/tests/components/cards/LazyBookCard.cy.js
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
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',
|
||||
libraryId: 'library-123',
|
||||
mediaType: 'book',
|
||||
media: {
|
||||
id: 'book1',
|
||||
metadata: { title: 'The Fellowship of the Ring', titleIgnorePrefix: 'Fellowship of the Ring', authorName: 'J. R. R. Tolkien', subtitle: 'The Lord of the Rings, Book 1' },
|
||||
numTracks: 1
|
||||
}
|
||||
}
|
||||
|
||||
const propsData = {
|
||||
index: 0,
|
||||
bookMount: book,
|
||||
bookshelfView: Constants.BookshelfView.DETAIL,
|
||||
continueListeningShelf: false,
|
||||
filterBy: null,
|
||||
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,
|
||||
'user/getUserSetting': (settingName) => false,
|
||||
'user/getSizeMultiplier': 1,
|
||||
'libraries/getLibraryProvider': () => 'audible.us',
|
||||
'libraries/getBookCoverAspectRatio': 1,
|
||||
'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()
|
||||
})
|
||||
|
||||
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('#cover-area-0').should(($el) => {
|
||||
const width = $el.width()
|
||||
const height = $el.height()
|
||||
const defaultHeight = 192
|
||||
const defaultWidth = defaultHeight
|
||||
|
||||
expect(width).to.be.closeTo(defaultWidth, 0.01)
|
||||
expect(height).to.be.closeTo(defaultHeight, 0.01)
|
||||
})
|
||||
})
|
||||
|
||||
it('shows subtitle when showSubtitles settings is true', () => {
|
||||
mountOptions.mocks.$store.getters['user/getUserSetting'] = (settingName) => {
|
||||
if (settingName === 'showSubtitles') return true
|
||||
}
|
||||
cy.mount(LazyBookCard, mountOptions)
|
||||
|
||||
cy.get('&titleImageNotReady').should('be.hidden')
|
||||
cy.get('&subtitle').should('be.visible').and('have.text', 'The Lord of the Rings, Book 1')
|
||||
})
|
||||
|
||||
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('&titleImageNotReady').should('be.hidden')
|
||||
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('&titleImageNotReady').should('be.hidden')
|
||||
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('&titleImageNotReady').should('be.hidden')
|
||||
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('&titleImageNotReady').should('be.hidden')
|
||||
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('&titleImageNotReady').should('be.hidden')
|
||||
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('&titleImageNotReady').should('be.hidden')
|
||||
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('&titleImageNotReady').should('be.hidden')
|
||||
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('&titleImageNotReady').should('be.hidden')
|
||||
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('&titleImageNotReady').should('be.hidden')
|
||||
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('&titleImageNotReady').should('be.hidden')
|
||||
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('&titleImageNotReady').should('be.hidden')
|
||||
cy.get('&progressBar')
|
||||
.should('be.visible')
|
||||
.and('have.class', 'bg-yellow-400')
|
||||
.and(($el) => {
|
||||
const width = $el.width()
|
||||
const defaultHeight = 192
|
||||
const defaultWidth = defaultHeight
|
||||
expect(width).to.be.closeTo(((1 + 0.5) / 3) * defaultWidth, 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('&titleImageNotReady').should('be.hidden')
|
||||
cy.get('&progressBar')
|
||||
.should('be.visible')
|
||||
.and('have.class', 'bg-success')
|
||||
.and(($el) => {
|
||||
const width = $el.width()
|
||||
const defaultHeight = 192
|
||||
const defaultWidth = defaultHeight
|
||||
expect(width).to.be.equal(defaultWidth)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
221
cypress/tests/components/cards/LazySeriesCard.cy.js
Normal file
221
cypress/tests/components/cards/LazySeriesCard.cy.js
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
import LazySeriesCard from '@/components/cards/LazySeriesCard.vue'
|
||||
import GroupCover from '@/components/covers/GroupCover.vue'
|
||||
|
||||
describe('LazySeriesCard', () => {
|
||||
const series = {
|
||||
id: 1,
|
||||
name: 'The Lord of the Rings',
|
||||
nameIgnorePrefix: 'Lord of the Rings',
|
||||
books: [
|
||||
{ id: 1, updatedAt: /* 04/14/2024 */ 1713099600000, addedAt: 1713099600000, media: { coverPath: 'cover1.jpg' }, title: 'The Fellowship of the Ring' },
|
||||
{ id: 2, updatedAt: /* 04/15/2024 */ 1713186000000, addedAt: 1713186000000, media: { coverPath: 'cover2.jpg' }, title: 'The Two Towers' },
|
||||
{ id: 3, updatedAt: /* 04/16/2024 */ 1713272400000, addedAt: 1713272400000, media: { coverPath: 'cover3.jpg' }, title: 'The Return of the King' }
|
||||
],
|
||||
addedAt: /* 04/17/2024 */ 1713358800000,
|
||||
totalDuration: /* 7h 30m */ 3600 * 7 + 60 * 30,
|
||||
rssFeed: 'https://example.com/feed.rss'
|
||||
}
|
||||
|
||||
const propsData = {
|
||||
index: 0,
|
||||
bookshelfView: 1,
|
||||
isCategorized: false,
|
||||
seriesMount: series,
|
||||
sortingIgnorePrefix: false,
|
||||
orderBy: 'addedAt'
|
||||
}
|
||||
|
||||
const stubs = {
|
||||
'covers-group-cover': GroupCover
|
||||
}
|
||||
|
||||
const mocks = {
|
||||
$store: {
|
||||
getters: {
|
||||
'user/getUserCanUpdate': true,
|
||||
'user/getUserMediaProgress': (id) => null,
|
||||
'user/getSizeMultiplier': 1,
|
||||
'libraries/getBookCoverAspectRatio': 1,
|
||||
'libraries/getLibraryProvider': () => 'audible.us',
|
||||
'globals/getLibraryItemCoverSrc': () => 'https://my.server.com/book_placeholder.jpg'
|
||||
},
|
||||
state: {
|
||||
libraries: {
|
||||
currentLibraryId: 'library-123'
|
||||
},
|
||||
serverSettings: {
|
||||
dateFormat: 'MM/dd/yyyy'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
before(() => {
|
||||
cy.intercept('GET', 'https://my.server.com/book_placeholder.jpg', { fixture: 'images/book_placeholder.jpg' }).as('bookCover')
|
||||
cy.mount(LazySeriesCard, { propsData, stubs, mocks })
|
||||
cy.wait('@bookCover')
|
||||
// Now the placeholder image is in the browser cache
|
||||
})
|
||||
|
||||
it('renders the component', () => {
|
||||
cy.mount(LazySeriesCard, { propsData, stubs, mocks })
|
||||
|
||||
cy.get('&covers-area').should(($el) => {
|
||||
const width = $el.width()
|
||||
const height = $el.height()
|
||||
const defailtHeight = 192
|
||||
const defaultWidth = defailtHeight * 2
|
||||
expect(width).to.be.closeTo(defaultWidth, 0.01)
|
||||
expect(height).to.be.closeTo(defailtHeight, 0.01)
|
||||
})
|
||||
cy.get('&seriesLengthMarker').should('be.visible').and('have.text', propsData.seriesMount.books.length)
|
||||
cy.get('&seriesProgressBar').should('not.exist')
|
||||
cy.get('&hoveringDisplayTitle').should('be.hidden')
|
||||
cy.get('&rssFeedMarker').should('be.visible')
|
||||
cy.get('&standardBottomDisplayTitle').should('not.exist')
|
||||
cy.get('&detailBottomDisplayTitle').should('be.visible')
|
||||
cy.get('&detailBottomDisplayTitle').should('have.text', 'The Lord of the Rings')
|
||||
cy.get('&detailBottomSortLine').should('have.text', 'Added 04/17/2024')
|
||||
})
|
||||
|
||||
it('shows series name and hides rss feed marker on mouseover', () => {
|
||||
cy.mount(LazySeriesCard, { propsData, stubs, mocks })
|
||||
cy.get('&card').trigger('mouseover')
|
||||
|
||||
cy.get('&hoveringDisplayTitle').should('be.visible').should('have.text', 'The Lord of the Rings')
|
||||
cy.get('&rssFeedMarker').should('not.exist')
|
||||
})
|
||||
|
||||
it('routes properly when clicked', () => {
|
||||
const updatedMocks = {
|
||||
...mocks,
|
||||
$router: {
|
||||
push: cy.stub().as('routerPush')
|
||||
}
|
||||
}
|
||||
cy.mount(LazySeriesCard, { propsData, stubs, mocks: updatedMocks })
|
||||
cy.get('&card').click()
|
||||
|
||||
cy.get('@routerPush').should('have.been.calledOnceWithExactly', '/library/library-123/series/1')
|
||||
})
|
||||
|
||||
it('shows progress bar when progress is available', () => {
|
||||
const updatedMocks = {
|
||||
...mocks,
|
||||
$store: {
|
||||
...mocks.$store,
|
||||
getters: {
|
||||
...mocks.$store.getters,
|
||||
'user/getUserMediaProgress': (id) => {
|
||||
switch (id) {
|
||||
case 1:
|
||||
return { isFinished: true }
|
||||
case 2:
|
||||
return { progress: 0.5 }
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cy.mount(LazySeriesCard, { propsData, stubs, mocks: updatedMocks })
|
||||
|
||||
cy.get('&seriesProgressBar')
|
||||
.should('be.visible')
|
||||
.and('have.class', 'bg-yellow-400')
|
||||
.and(($el) => {
|
||||
const width = $el.width()
|
||||
const defailtHeight = 192
|
||||
const defaultWidth = defailtHeight * 2
|
||||
expect(width).to.be.closeTo(((1 + 0.5) / 3) * defaultWidth, 0.01)
|
||||
})
|
||||
})
|
||||
|
||||
it('shows full green progress bar when all books are finished', () => {
|
||||
const updatedMocks = {
|
||||
...mocks,
|
||||
$store: {
|
||||
...mocks.$store,
|
||||
getters: {
|
||||
...mocks.$store.getters,
|
||||
'user/getUserMediaProgress': (id) => {
|
||||
return { isFinished: true }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cy.mount(LazySeriesCard, { propsData, stubs, mocks: updatedMocks })
|
||||
|
||||
cy.get('&seriesProgressBar')
|
||||
.should('be.visible')
|
||||
.and('have.class', 'bg-success')
|
||||
.and(($el) => {
|
||||
const width = $el.width()
|
||||
const defailtHeight = 192
|
||||
const defaultWidth = defailtHeight * 2
|
||||
expect(width).to.equal(defaultWidth)
|
||||
})
|
||||
})
|
||||
|
||||
it('hides the rss feed marker when there is no rss feed', () => {
|
||||
const updatedPropsData = {
|
||||
...propsData,
|
||||
seriesMount: { ...series, rssFeed: null }
|
||||
}
|
||||
cy.mount(LazySeriesCard, { propsData: updatedPropsData, stubs, mocks })
|
||||
|
||||
cy.get('&rssFeedMarker').should('not.exist')
|
||||
})
|
||||
|
||||
it('shows the standard bottom display when bookshelf view is 0', () => {
|
||||
const updatedPropsData = {
|
||||
...propsData,
|
||||
bookshelfView: 0
|
||||
}
|
||||
cy.mount(LazySeriesCard, { propsData: updatedPropsData, stubs, mocks })
|
||||
|
||||
cy.get('&standardBottomDisplayTitle').should('be.visible')
|
||||
cy.get('&detailBottomDisplayTitle').should('not.exist')
|
||||
})
|
||||
|
||||
it('shows total duration in sort line when orderBy is totalDuration', () => {
|
||||
const updatedPropsData = {
|
||||
...propsData,
|
||||
orderBy: 'totalDuration'
|
||||
}
|
||||
cy.mount(LazySeriesCard, { propsData: updatedPropsData, stubs, mocks })
|
||||
|
||||
cy.get('&detailBottomSortLine').should('have.text', 'Duration 7h 30m')
|
||||
})
|
||||
|
||||
it('shows last book updated date in sort line when orderBy is lastBookUpdated', () => {
|
||||
const updatedPropsData = {
|
||||
...propsData,
|
||||
orderBy: 'lastBookUpdated'
|
||||
}
|
||||
cy.mount(LazySeriesCard, { propsData: updatedPropsData, stubs, mocks })
|
||||
|
||||
cy.get('&detailBottomSortLine').should('have.text', 'Last Book Updated 04/16/2024')
|
||||
})
|
||||
|
||||
it('shows last book added date in sort line when orderBy is lastBookAdded', () => {
|
||||
const updatedPropsData = {
|
||||
...propsData,
|
||||
orderBy: 'lastBookAdded'
|
||||
}
|
||||
cy.mount(LazySeriesCard, { propsData: updatedPropsData, stubs, mocks })
|
||||
|
||||
cy.get('&detailBottomSortLine').should('have.text', 'Last Book Added 04/16/2024')
|
||||
})
|
||||
|
||||
it('shows nameIgnorePrefix when sortingIgnorePrefix is true', () => {
|
||||
const updatedPropsData = {
|
||||
...propsData,
|
||||
sortingIgnorePrefix: true
|
||||
}
|
||||
cy.mount(LazySeriesCard, { propsData: updatedPropsData, stubs, mocks })
|
||||
|
||||
cy.get('&detailBottomDisplayTitle').should('have.text', 'Lord of the Rings')
|
||||
})
|
||||
})
|
||||
84
cypress/tests/components/cards/NarratorCard.cy.js
Normal file
84
cypress/tests/components/cards/NarratorCard.cy.js
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
import NarratorCard from '@/components/cards/NarratorCard.vue'
|
||||
|
||||
describe('<NarratorCard />', () => {
|
||||
const narrator = {
|
||||
name: 'John Doe',
|
||||
numBooks: 5
|
||||
}
|
||||
const propsData = {
|
||||
narrator
|
||||
}
|
||||
const mocks = {
|
||||
$store: {
|
||||
getters: {
|
||||
'user/getUserCanUpdate': true,
|
||||
'user/getSizeMultiplier': 1
|
||||
},
|
||||
state: {
|
||||
libraries: {
|
||||
currentLibraryId: 'library-123'
|
||||
}
|
||||
}
|
||||
},
|
||||
$encode: (value) => value
|
||||
}
|
||||
|
||||
it('renders the component', () => {
|
||||
let mountOptions = { propsData, mocks }
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
cy.mount(NarratorCard, mountOptions)
|
||||
})
|
||||
|
||||
it('renders the narrator name correctly', () => {
|
||||
let mountOptions = { propsData, mocks }
|
||||
cy.mount(NarratorCard, mountOptions)
|
||||
|
||||
cy.get('&name').should('have.text', 'John Doe')
|
||||
})
|
||||
|
||||
it('renders the number of books correctly', () => {
|
||||
let mountOptions = { propsData, mocks }
|
||||
cy.mount(NarratorCard, mountOptions)
|
||||
|
||||
cy.get('&numBooks').should('have.text', '5 Books')
|
||||
})
|
||||
|
||||
it('renders 1 book correctly', () => {
|
||||
let propsData = { narrator: { name: 'John Doe', numBooks: 1 }, width: 200, height: 150 }
|
||||
let mountOptions = { propsData, mocks }
|
||||
cy.mount(NarratorCard, mountOptions)
|
||||
|
||||
cy.get('&numBooks').should('have.text', '1 Book')
|
||||
})
|
||||
|
||||
it('renders the default name and num-books when narrator is not provided', () => {
|
||||
let propsData = { width: 200, height: 150 }
|
||||
let mountOptions = { propsData, mocks }
|
||||
cy.mount(NarratorCard, mountOptions)
|
||||
cy.get('&name').should('have.text', '')
|
||||
cy.get('&numBooks').should('have.text', '0 Books')
|
||||
})
|
||||
|
||||
it('has the correct width and height', () => {
|
||||
let mountOptions = { propsData, mocks }
|
||||
cy.mount(NarratorCard, mountOptions)
|
||||
cy.get('&card').should('have.css', 'width', '150px')
|
||||
cy.get('&card').should('have.css', 'height', '100px')
|
||||
})
|
||||
|
||||
it('has the correct width and height when not provided', () => {
|
||||
let propsData = { narrator }
|
||||
let mountOptions = { propsData, mocks }
|
||||
cy.mount(NarratorCard, mountOptions)
|
||||
cy.get('&card').should('have.css', 'width', '150px')
|
||||
cy.get('&card').should('have.css', 'height', '100px')
|
||||
})
|
||||
|
||||
it('has the correct font sizes', () => {
|
||||
let mountOptions = { propsData, mocks }
|
||||
cy.mount(NarratorCard, mountOptions)
|
||||
const defaultFontSize = 16
|
||||
cy.get('&name').should('have.css', 'font-size', `${0.75 * defaultFontSize}px`)
|
||||
cy.get('&numBooks').should('have.css', 'font-size', `${0.65 * defaultFontSize}px`)
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue