Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions packages/gatsby-image/src/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,22 @@ const setupImages = (
}

describe(`<Image />`, () => {
const OLD_MATCH_MEDIA = window.matchMedia
Comment thread
pvdz marked this conversation as resolved.
beforeEach(() => {
window.matchMedia = jest.fn(media =>
media === `only screen and (min-width: 1024px)`
? {
matches: true,
}
: {
matches: false,
}
)
})
afterEach(() => {
window.matchMedia = OLD_MATCH_MEDIA
})

it(`should render fixed size images`, () => {
const component = setup()
expect(component).toMatchSnapshot()
Expand Down Expand Up @@ -204,6 +220,66 @@ describe(`<Image />`, () => {
expect(console.warn).toBeCalled()
})

it(`should select the correct mocked image of fluid variants provided.`, () => {
const tripleFluidImageShapeMock = fluidImagesShapeMock.concat({
aspectRatio: 5,
src: `test_image_4.jpg`,
srcSet: `third other srcSet`,
srcSetWebp: `third other srcSetWebp`,
sizes: `(max-width: 1920px) 100vw, 1920px`,
base64: `string_of_base64`,
media: `only screen and (min-width: 1024px)`,
})
const { container } = render(
<Image
backgroundColor
className={`fluidArtDirectedImage`}
style={{ display: `inline` }}
title={`Title for the image`}
alt={`Alt text for the image`}
crossOrigin={`anonymous`}
fluid={tripleFluidImageShapeMock}
itemProp={`item-prop-for-the-image`}
placeholderStyle={{ color: `red` }}
placeholderClassName={`placeholder`}
/>
)
const aspectPreserver = container.querySelector(`div div div`)
expect(aspectPreserver.getAttribute(`style`)).toEqual(
expect.stringMatching(/padding-bottom: 20%/)
)
})

it(`should select the correct mocked image of fixed variants provided.`, () => {
const tripleFixedImageShapeMock = fixedImagesShapeMock.concat({
width: 1024,
height: 768,
src: `test_image_4.jpg`,
srcSet: `third other srcSet`,
srcSetWebp: `third other srcSetWebp`,
base64: `string_of_base64`,
media: `only screen and (min-width: 1024px)`,
})
const { container } = render(
<Image
backgroundColor
className={`fixedArtDirectedImage`}
style={{ display: `inline` }}
title={`Title for the image`}
alt={`Alt text for the image`}
crossOrigin={`anonymous`}
fixed={tripleFixedImageShapeMock}
itemProp={`item-prop-for-the-image`}
placeholderStyle={{ color: `red` }}
placeholderClassName={`placeholder`}
/>
)
const aspectPreserver = container.querySelector(`div div`)
expect(aspectPreserver.getAttribute(`style`)).toEqual(
expect.stringMatching(/width: 1024px; height: 768px;/)
)
})

it(`should call onLoad and onError image events`, () => {
const onLoadMock = jest.fn()
const onErrorMock = jest.fn()
Expand Down
44 changes: 40 additions & 4 deletions packages/gatsby-image/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,54 @@ const convertProps = props => {
return convertedProps
}

/**
* Checks if fluid or fixed are art-direction arrays.
*
* @param currentData {{media?: string}[]} The props to check for images.
* @return {boolean}
Comment thread
timhagn marked this conversation as resolved.
*/
const hasArtDirectionSupport = currentData =>
!!currentData &&
Array.isArray(currentData) &&
currentData.some(image => typeof image.media !== `undefined`)

/**
* Tries to detect if a media query matches the current viewport.
* @property media {{media?: string}} A media query string.
* @return {boolean}
*/
const matchesMedia = ({ media }) =>
media ? isBrowser && !!window.matchMedia(media).matches : false

/**
* Find the source of an image to use as a key in the image cache.
* Use `the first image in either `fixed` or `fluid`
* @param {{fluid: {src: string}[], fixed: {src: string}[]}} args
* @param {{fluid: {src: string, media?: string}[], fixed: {src: string, media?: string}[]}} args
* @return {string}
*/
const getImageSrcKey = ({ fluid, fixed }) => {
const data = (fluid && fluid[0]) || (fixed && fixed[0])
const data = fluid ? getCurrentSrcData(fluid) : getCurrentSrcData(fixed)

return data.src
}

/**
* Returns the current src - Preferably with art-direction support.
* @param currentData {{media?: string}[]} The fluid or fixed image array.
* @return {{src: string, media?: string}}
*/
const getCurrentSrcData = currentData => {
if (isBrowser && hasArtDirectionSupport(currentData)) {
// Do we have an image for the current Viewport?
const foundMedia = currentData.findIndex(matchesMedia)
if (foundMedia !== -1) {
return currentData[foundMedia]
}
}
// Else return the first image.
return currentData[0]
}

// Cache if we've seen an image before so we don't bother with
// lazy-loading & fading in on subsequent mounts.
const imageCache = Object.create({})
Expand Down Expand Up @@ -416,7 +452,7 @@ class Image extends React.Component {

if (fluid) {
const imageVariants = fluid
const image = imageVariants[0]
const image = getCurrentSrcData(fluid)

return (
<Tag
Expand Down Expand Up @@ -516,7 +552,7 @@ class Image extends React.Component {

if (fixed) {
const imageVariants = fixed
const image = imageVariants[0]
const image = getCurrentSrcData(fixed)

const divStyle = {
position: `relative`,
Expand Down