Skip to content

Commit

Permalink
Merge pull request #177 from vtex-apps/feat/changeonhover
Browse files Browse the repository at this point in the history
create prop change on hover for image
  • Loading branch information
jgfidelis committed Aug 6, 2019
2 parents ee6f850 + 55fd1a7 commit 979434e
Show file tree
Hide file tree
Showing 16 changed files with 388 additions and 129 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- Prop `hoverImageLabel` to `product-summary-image`.
- Created function to normalize product-summary and use it uniformly in other components.

## [2.31.0] - 2019-08-01
### Added
Expand Down
3 changes: 2 additions & 1 deletion manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
"vtex.product-identifier": "0.x",
"vtex.styleguide": "9.x",
"vtex.pixel-manager": "1.x",
"vtex.product-teaser-interfaces": "1.x"
"vtex.product-teaser-interfaces": "1.x",
"vtex.device-detector": "0.x"
},
"$schema": "https://raw.githubusercontent.com/vtex/node-vtex-api/master/gen/manifest.schema"
}
5 changes: 4 additions & 1 deletion messages/context.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,8 @@
"admin/editor.productSummaryPrice.showLabels.title": "Title of showLabels prop",
"admin/editor.productSummaryPrice.labelSellingPrice.title": "Title of labelSellingPrice prop",
"admin/editor.productSummaryPrice.labelListPrice.title": "Title of labelListPrice prop",
"admin/editor.productSummaryPrice.showBorders.title": "Title of showBorders prop"
"admin/editor.productSummaryPrice.showBorders.title": "Title of showBorders prop",
"admin/editor.productSummaryImage.title": "admin/editor.productSummaryImage.title",
"admin/editor.productSummaryImage.description": "admin/editor.productSummaryImage.description",
"admin/editor.productSummaryImage.hoverImageLabel.title": "admin/editor.productSummaryImage.hoverImageLabel.title"
}
7 changes: 5 additions & 2 deletions messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,8 @@
"admin/editor.productSummaryPrice.showLabels.title": "Show labels",
"admin/editor.productSummaryPrice.labelSellingPrice.title": "Label for selling price",
"admin/editor.productSummaryPrice.labelListPrice.title": "Label for list price",
"admin/editor.productSummaryPrice.showBorders.title": "Show borders"
}
"admin/editor.productSummaryPrice.showBorders.title": "Show borders",
"admin/editor.productSummaryImage.title": "Product Summary Image",
"admin/editor.productSummaryImage.description": "The component that shows the product image",
"admin/editor.productSummaryImage.hoverImageLabel.title": "Hover Image Label"
}
7 changes: 5 additions & 2 deletions messages/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,8 @@
"admin/editor.productSummaryPrice.showLabels.title": "Mostrar las etiquetas",
"admin/editor.productSummaryPrice.labelSellingPrice.title": "Etiqueta para el precio de venta",
"admin/editor.productSummaryPrice.labelListPrice.title": "Etiqueta para el precio indicado",
"admin/editor.productSummaryPrice.showBorders.title": "Mostrar bordes"
}
"admin/editor.productSummaryPrice.showBorders.title": "Mostrar bordes",
"admin/editor.productSummaryImage.title": "Imagen de resumen del producto",
"admin/editor.productSummaryImage.description": "El componente que muestra la imagen del producto",
"admin/editor.productSummaryImage.hoverImageLabel.title": "Etiqueta de imagen secundaria"
}
7 changes: 5 additions & 2 deletions messages/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,8 @@
"admin/editor.productSummaryPrice.showLabels.title": "Mostrar rótulos",
"admin/editor.productSummaryPrice.labelSellingPrice.title": "Rótulo para preço de venda",
"admin/editor.productSummaryPrice.labelListPrice.title": "Rótulo para preço listado",
"admin/editor.productSummaryPrice.showBorders.title": "Mostrar bordas"
}
"admin/editor.productSummaryPrice.showBorders.title": "Mostrar bordas",
"admin/editor.productSummaryImage.title": "Imagem do Resumo do produto",
"admin/editor.productSummaryImage.description": "O componente que mostra a imagem do produto",
"admin/editor.productSummaryImage.hoverImageLabel.title": "Rótulo da imagem secundária"
}
1 change: 1 addition & 0 deletions react/__mocks__/vtex.device-detector.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const useDevice = () => ({ isMobile: true, device: 'desktop' })
154 changes: 55 additions & 99 deletions react/__tests__/ProductSummary.test.js
Original file line number Diff line number Diff line change
@@ -1,117 +1,73 @@
import React from 'react'
import { render } from '@vtex/test-tools/react'
import fs from 'fs'

import ProductSummary from '../legacy/index'
import ProductSummary from '../ProductSummaryCustom'

describe('<ProductSummary /> component', () => {
// TODO: Remove this later when we have a better way to resolve contentSchemas.json at test-tools
const rawData = fs.readFileSync('../store/contentSchemas.json')
const contentSchema = JSON.parse(rawData)
const buyButtonText =
contentSchema.definitions.ProductSummary.properties.buyButtonText.default

const props = {
runtime: { hints: {} },
buyButtonText,
product: {
it(`should parse a product succesfully and get sku as the first with available quantity`, () => {
const product = {
productId: '123456789',
linkText: 'linkText',
productName: 'productName',
sku: {
name: 'name',
itemId: 'itemId',
image: {
imageUrl: '',
items: [
{
itemId: '1',
name: 'item 1',
sellers: [
{
sellerId: '1',
commertialOffer: {
AvailableQuantity: 0,
Price: 10,
},
},
],
images: [
{
imageUrl: 'image1',
imageLabel: null,
},
{
imageUrl: 'image2',
imageLabel: null,
},
],
},
seller: {
sellerId: 'sellerId',
commertialOffer: {
Installments: [
{
Value: 1,
InterestRate: 1,
NumberOfInstallments: 1,
{
itemId: '2',
name: 'item 2',
sellers: [
{
sellerId: '1',
commertialOffer: {
AvailableQuantity: 3,
Price: 15,
},
],
Price: 1,
ListPrice: 1,
},
},
],
images: [
{
imageUrl: 'image1',
imageLabel: null,
},
{
imageUrl: 'image2',
imageLabel: null,
},
],
},
},
],
productClusters: [
{
name: 'name',
},
],
quantity: 1,
},
}

function renderComponent(customProps) {
return render(<ProductSummary {...props} {...customProps} />)
}

it('should match the snapshot for normal mode', () => {
const { asFragment } = renderComponent({ displayMode: 'normal' })
expect(asFragment()).toMatchSnapshot()
})

it('should match the snapshot for small mode', () => {
const { asFragment } = renderComponent({ displayMode: 'small' })
expect(asFragment()).toMatchSnapshot()
})

it('should match the snapshot for inline normal mode', () => {
const { asFragment } = renderComponent({ displayMode: 'inline' })
expect(asFragment()).toMatchSnapshot()
})

it('should match the snapshot for inline price mode', () => {
const { asFragment } = renderComponent({ displayMode: 'inlinePrice' })
expect(asFragment()).toMatchSnapshot()
}
const result = ProductSummary.mapCatalogProductToProductSummary(product)
expect(result).toBeDefined()
expect(result.sku.seller.sellerId).toBe('1')
expect(result.sku.image).toBeDefined()
expect(result.sku.itemId).toBe('2')
})

it('should render buy button in inline, small and normal mode', () => {
const { getByText, rerender, container } = renderComponent({
displayMode: 'normal',
})
expect(getByText('Buy')).toBeTruthy()

rerender(<ProductSummary {...props} displayMode="small" />)
expect(getByText('Buy')).toBeTruthy()

rerender(<ProductSummary {...props} displayMode="inline" />)
expect(getByText('Buy')).toBeTruthy()

rerender(<ProductSummary {...props} displayMode="inlinePrice" />)
expect(container.querySelector('.buyButtonContainer')).toBeFalsy()
})

it('should render quantity stepper only in inline price mode', () => {
const { container, rerender } = renderComponent({ displayMode: 'normal' })
expect(container.querySelector('.quantityStepperContainer')).toBeFalsy()

rerender(<ProductSummary {...props} displayMode="inlinePrice" />)
expect(container.querySelector('.quantityStepperContainer')).toBeTruthy()

rerender(<ProductSummary {...props} displayMode="small" />)
expect(container.querySelector('.quantityStepperContainer')).toBeFalsy()

rerender(<ProductSummary {...props} displayMode="inline" />)
expect(container.querySelector('.quantityStepperContainer')).toBeFalsy()
})

it(`should not break Shelf getSchema`, () => {
it(`should not break ProductSummary getSchema`, () => {
expect(ProductSummary.getSchema).toEqual(expect.any(Function))
})

describe('Site editor editable', () => {
it('should export getSchema and return object with title', () => {
const schema = ProductSummary.schema || ProductSummary.getSchema({})
expect(schema).toEqual(
expect.objectContaining({ title: expect.any(String) })
)
})
})
})
117 changes: 117 additions & 0 deletions react/__tests__/ProductSummaryLegacy.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import React from 'react'
import { render } from '@vtex/test-tools/react'
import fs from 'fs'

import ProductSummary from '../legacy/index'

describe('<ProductSummary /> component', () => {
// TODO: Remove this later when we have a better way to resolve contentSchemas.json at test-tools
const rawData = fs.readFileSync('../store/contentSchemas.json')
const contentSchema = JSON.parse(rawData)
const buyButtonText =
contentSchema.definitions.ProductSummary.properties.buyButtonText.default

const props = {
runtime: { hints: {} },
buyButtonText,
product: {
productId: '123456789',
linkText: 'linkText',
productName: 'productName',
sku: {
name: 'name',
itemId: 'itemId',
image: {
imageUrl: '',
},
seller: {
sellerId: 'sellerId',
commertialOffer: {
Installments: [
{
Value: 1,
InterestRate: 1,
NumberOfInstallments: 1,
},
],
Price: 1,
ListPrice: 1,
},
},
},
productClusters: [
{
name: 'name',
},
],
quantity: 1,
},
}

function renderComponent(customProps) {
return render(<ProductSummary {...props} {...customProps} />)
}

it('should match the snapshot for normal mode', () => {
const { asFragment } = renderComponent({ displayMode: 'normal' })
expect(asFragment()).toMatchSnapshot()
})

it('should match the snapshot for small mode', () => {
const { asFragment } = renderComponent({ displayMode: 'small' })
expect(asFragment()).toMatchSnapshot()
})

it('should match the snapshot for inline normal mode', () => {
const { asFragment } = renderComponent({ displayMode: 'inline' })
expect(asFragment()).toMatchSnapshot()
})

it('should match the snapshot for inline price mode', () => {
const { asFragment } = renderComponent({ displayMode: 'inlinePrice' })
expect(asFragment()).toMatchSnapshot()
})

it('should render buy button in inline, small and normal mode', () => {
const { getByText, rerender, container } = renderComponent({
displayMode: 'normal',
})
expect(getByText('Buy')).toBeTruthy()

rerender(<ProductSummary {...props} displayMode="small" />)
expect(getByText('Buy')).toBeTruthy()

rerender(<ProductSummary {...props} displayMode="inline" />)
expect(getByText('Buy')).toBeTruthy()

rerender(<ProductSummary {...props} displayMode="inlinePrice" />)
expect(container.querySelector('.buyButtonContainer')).toBeFalsy()
})

it('should render quantity stepper only in inline price mode', () => {
const { container, rerender } = renderComponent({ displayMode: 'normal' })
expect(container.querySelector('.quantityStepperContainer')).toBeFalsy()

rerender(<ProductSummary {...props} displayMode="inlinePrice" />)
expect(container.querySelector('.quantityStepperContainer')).toBeTruthy()

rerender(<ProductSummary {...props} displayMode="small" />)
expect(container.querySelector('.quantityStepperContainer')).toBeFalsy()

rerender(<ProductSummary {...props} displayMode="inline" />)
expect(container.querySelector('.quantityStepperContainer')).toBeFalsy()
})

it(`should not break Shelf getSchema`, () => {
expect(ProductSummary.getSchema).toEqual(expect.any(Function))
})

describe('Site editor editable', () => {
it('should export getSchema and return object with title', () => {
const schema = ProductSummary.schema || ProductSummary.getSchema({})
expect(schema).toEqual(
expect.objectContaining({ title: expect.any(String) })
)
})
})
})
5 changes: 5 additions & 0 deletions react/components/ProductSummary.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
} from 'vtex.product-summary-context/ProductSummaryContext'
import productSummary from '../productSummary.css'
import { productShape } from '../utils/propTypes'
import { mapCatalogProductToProductSummary } from '../utils/normarlize'

const ProductSummaryCustom = ({ product, actionOnClick, children }) => {
const { isLoading, isHovering } = useProductSummary()
Expand Down Expand Up @@ -114,4 +115,8 @@ ProductSummaryWrapper.getSchema = () => {
}
}

// This function is public available to be used only by vtex.shelf and vtex.search-result.
// We do not garantee this API will not change and might happen breaking change anytime.
ProductSummaryWrapper.mapCatalogProductToProductSummary = mapCatalogProductToProductSummary

export default ProductSummaryWrapper
Loading

0 comments on commit 979434e

Please sign in to comment.