diff --git a/packages/peregrine/package.json b/packages/peregrine/package.json index c5bfd28a1c3..99ae9cbf23e 100644 --- a/packages/peregrine/package.json +++ b/packages/peregrine/package.json @@ -13,7 +13,7 @@ "url": "https://github.com/magento-research/peregrine" }, "scripts": { - "build": "babel src -d dist --ignore test.js", + "build": "babel src -d dist --ignore '*.test.js,*.spec.js'", "danger": "danger-ci", "clean": "rimraf dist", "prepare": "npm-merge-driver install", diff --git a/packages/peregrine/src/List/__tests__/items.spec.js b/packages/peregrine/src/List/__tests__/items.spec.js index 5b90e545a7c..18f8d388e8e 100644 --- a/packages/peregrine/src/List/__tests__/items.spec.js +++ b/packages/peregrine/src/List/__tests__/items.spec.js @@ -6,11 +6,38 @@ import { Items } from '..'; configure({ adapter: new Adapter() }); -const items = Object.entries({ - a: { id: 'a', val: '10' }, - b: { id: 'b', val: '20' }, - c: { id: 'c', val: '30' } -}); +const items = [ + [ + 1, + { + id: 1, + name: 'Test Product 1', + small_image: '/test/product/1.png', + price: { + regularPrice: { + amount: { + value: 100 + } + } + } + } + ], + [ + 2, + { + id: 2, + name: 'Test Product 2', + small_image: '/test/product/2.png', + price: { + regularPrice: { + amount: { + value: 100 + } + } + } + } + ] +]; test('renders a fragment', () => { const props = { items }; @@ -61,7 +88,7 @@ test('passes correct props to each child', () => { wrapper.children().forEach((node, i) => { const [key, item] = items[i]; - expect(node.key()).toEqual(key); + expect(node.key()).toEqual(key.toString()); expect(node.props()).toMatchObject({ item, render: props.renderItem, @@ -158,13 +185,13 @@ test('updates radio `selection` on child click', () => { expect(wrapper.state('selection')).toEqual(new Set()); wrapper.childAt(0).simulate('click'); - expect(wrapper.state('selection')).toEqual(new Set(['a'])); + expect(wrapper.state('selection')).toEqual(new Set([1])); wrapper.childAt(1).simulate('click'); - expect(wrapper.state('selection')).toEqual(new Set(['b'])); + expect(wrapper.state('selection')).toEqual(new Set([2])); wrapper.childAt(0).simulate('click'); - expect(wrapper.state('selection')).toEqual(new Set(['a'])); + expect(wrapper.state('selection')).toEqual(new Set([1])); }); test('updates checkbox `selection` on child click', () => { @@ -174,13 +201,13 @@ test('updates checkbox `selection` on child click', () => { expect(wrapper.state('selection')).toEqual(new Set()); wrapper.childAt(0).simulate('click'); - expect(wrapper.state('selection')).toEqual(new Set(['a'])); + expect(wrapper.state('selection')).toEqual(new Set([1])); wrapper.childAt(1).simulate('click'); - expect(wrapper.state('selection')).toEqual(new Set(['a', 'b'])); + expect(wrapper.state('selection')).toEqual(new Set([1, 2])); wrapper.childAt(0).simulate('click'); - expect(wrapper.state('selection')).toEqual(new Set(['b'])); + expect(wrapper.state('selection')).toEqual(new Set([2])); }); test('calls `syncSelection` after updating selection', () => { diff --git a/packages/venia-concept/babel.config.js b/packages/venia-concept/babel.config.js index 27f9296bad8..ced1489e31d 100644 --- a/packages/venia-concept/babel.config.js +++ b/packages/venia-concept/babel.config.js @@ -7,7 +7,8 @@ const plugins = [ 'syntax-jsx', 'transform-class-properties', 'transform-object-rest-spread', - ['transform-react-jsx', { pragma: 'createElement' }] + ['transform-react-jsx', { pragma: 'createElement' }], + 'graphql-tag' ]; // define default babel options diff --git a/packages/venia-concept/jest.config.js b/packages/venia-concept/jest.config.js index 75038b8069a..b8ad410a2fc 100644 --- a/packages/venia-concept/jest.config.js +++ b/packages/venia-concept/jest.config.js @@ -4,5 +4,8 @@ module.exports = { moduleNameMapper: { '\\.css$': 'identity-obj-proxy', '^src/(.+)': '/src/$1' - } + }, + // We don't ship Peregrine with CSJ support (intentional), so transpile + // used Peregrine code in tests + transformIgnorePatterns: ['node_modules/(?!@magento/peregrine)'] }; diff --git a/packages/venia-concept/package-lock.json b/packages/venia-concept/package-lock.json index e63e4f2fc45..96019eb7a96 100644 --- a/packages/venia-concept/package-lock.json +++ b/packages/venia-concept/package-lock.json @@ -9,12 +9,28 @@ "resolved": "https://registry.npmjs.org/@magento/peregrine/-/peregrine-0.3.0.tgz", "integrity": "sha512-UH5liQ73tPt3VfLv4pHSpX96U10fkp9/O6U3h4ydtJ9Bmb8DHRPZheOJV4WMAO4U+M7mEzaMB0m3VTywKbM5ow==" }, + "@types/async": { + "version": "2.0.49", + "resolved": "https://registry.npmjs.org/@types/async/-/async-2.0.49.tgz", + "integrity": "sha512-Benr3i5odUkvpFkOpzGqrltGdbSs+EVCkEBGXbuR7uT0VzhXKIkhem6PDzHdx5EonA+rfbB3QvP6aDOw5+zp5Q==", + "optional": true + }, + "@types/graphql": { + "version": "0.12.6", + "resolved": "https://registry.npmjs.org/@types/graphql/-/graphql-0.12.6.tgz", + "integrity": "sha512-wXAVyLfkG1UMkKOdMijVWFky39+OD/41KftzqfX1Oejd0Gm6dOIKjCihSVECg6X7PHjftxXmfOKA/d1H79ZfvQ==" + }, "@types/node": { "version": "9.6.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.6.tgz", "integrity": "sha512-SJe0g5cZeGNDP5sD8mIX3scb+eq8LQQZ60FXiKZHipYSeEFZ5EKml+NNMiO76F74TY4PoMWlNxF/YRY40FOvZQ==", "dev": true }, + "@types/zen-observable": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.5.4.tgz", + "integrity": "sha512-sW6xN96wUak4tgc89d0tbTg7QDGYhGv5hvQIS6h4mRCd8h2btiZ80loPU8cyLwsBbA4ZeQt0FjvUhJ4rNhdsGg==" + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -123,6 +139,114 @@ "normalize-path": "^2.1.1" } }, + "apollo-boost": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/apollo-boost/-/apollo-boost-0.1.9.tgz", + "integrity": "sha512-OX+XyyOwUhpi9gaUeYl/3D3FDFc5v2fb0M4fzQnRPep0T5zemB9AVcoK5yLWOnn6VOKSNcfeN9iPHvCpEHjPgA==", + "requires": { + "apollo-cache": "^1.1.11", + "apollo-cache-inmemory": "^1.2.4", + "apollo-client": "^2.3.4", + "apollo-link": "^1.0.6", + "apollo-link-error": "^1.0.3", + "apollo-link-http": "^1.3.1", + "apollo-link-state": "^0.4.0", + "graphql-tag": "^2.4.2" + } + }, + "apollo-cache": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/apollo-cache/-/apollo-cache-1.1.11.tgz", + "integrity": "sha512-U1wgLVelBpxF16fZzQMlOBiXRw7B6QSBSwFDRtuefo+Nh13wpWgHoZhqoQCwjNmmUWXgbL8JjH+TJCMuUtAxWQ==", + "requires": { + "apollo-utilities": "^1.0.15" + } + }, + "apollo-cache-inmemory": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/apollo-cache-inmemory/-/apollo-cache-inmemory-1.2.4.tgz", + "integrity": "sha512-F1dsS3S6WMcX1eoykltryPwV3LHZKUJgBgLcUBJjpvDu6C8cdE+aN6V6rbIm76lNWZKncy8afs+0brn0a+TUUQ==", + "requires": { + "apollo-cache": "^1.1.11", + "apollo-utilities": "^1.0.15", + "graphql-anywhere": "^4.1.13" + } + }, + "apollo-client": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/apollo-client/-/apollo-client-2.3.4.tgz", + "integrity": "sha512-h0ny/QzAakACbmayzDHNLAV8K92HsBgGC64mGogPgeWaqgKJ64VmmdkV4TtELkMwVGjd7Tq2oSl0LfywJjZrtA==", + "requires": { + "@types/async": "2.0.49", + "@types/zen-observable": "^0.5.3", + "apollo-cache": "^1.1.11", + "apollo-link": "^1.0.0", + "apollo-link-dedup": "^1.0.0", + "apollo-utilities": "^1.0.15", + "symbol-observable": "^1.0.2", + "zen-observable": "^0.8.0" + } + }, + "apollo-link": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/apollo-link/-/apollo-link-1.2.2.tgz", + "integrity": "sha512-Uk/BC09dm61DZRDSu52nGq0nFhq7mcBPTjy5EEH1eunJndtCaNXQhQz/BjkI2NdrfGI+B+i5he6YSoRBhYizdw==", + "requires": { + "@types/graphql": "0.12.6", + "apollo-utilities": "^1.0.0", + "zen-observable-ts": "^0.8.9" + } + }, + "apollo-link-dedup": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/apollo-link-dedup/-/apollo-link-dedup-1.0.9.tgz", + "integrity": "sha512-RbuEKpmSHVMtoREMPh2wUFTeh65q+0XPVeqgaOP/rGEAfvLyOMvX0vT2nVaejMohoMxuUnfZwpldXaDFWnlVbg==", + "requires": { + "apollo-link": "^1.2.2" + } + }, + "apollo-link-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/apollo-link-error/-/apollo-link-error-1.1.0.tgz", + "integrity": "sha512-4Vu/IUn6Kn6+Fthym4iuqypCKcLdwTg3MaCvtLdaLbt9X2hNCq3y8mv6vuWIlAY51X8wKhCgYghQSOs5R/embQ==", + "requires": { + "apollo-link": "^1.2.2" + } + }, + "apollo-link-http": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/apollo-link-http/-/apollo-link-http-1.5.4.tgz", + "integrity": "sha512-e9Ng3HfnW00Mh3TI6DhNRfozmzQOtKgdi+qUAsHBOEcTP0PTAmb+9XpeyEEOueLyO0GXhB92HUCIhzrWMXgwyg==", + "requires": { + "apollo-link": "^1.2.2", + "apollo-link-http-common": "^0.2.4" + } + }, + "apollo-link-http-common": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/apollo-link-http-common/-/apollo-link-http-common-0.2.4.tgz", + "integrity": "sha512-4j6o6WoXuSPen9xh4NBaX8/vL98X1xY2cYzUEK1F8SzvHe2oFONfxJBTekwU8hnvapcuq8Qh9Uct+gelu8T10g==", + "requires": { + "apollo-link": "^1.2.2" + } + }, + "apollo-link-state": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/apollo-link-state/-/apollo-link-state-0.4.1.tgz", + "integrity": "sha512-69/til4ENfl/Fvf7br2xSsLSBcxcXPbOHVNkzLLejvUZickl93HLO4/fO+uvoBi4dCYRgN17Zr8FwI41ueRx0g==", + "requires": { + "apollo-utilities": "^1.0.8", + "graphql-anywhere": "^4.1.0-alpha.0" + } + }, + "apollo-utilities": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/apollo-utilities/-/apollo-utilities-1.0.15.tgz", + "integrity": "sha512-74/oBQhIfWKgkwNJZoBVOLfmAZQlwUSCb4fEzd4sNFOkJL1CscmBge+YHhmTyKRQnwz0BYjWfLx4T99/jhF7CA==", + "requires": { + "fast-json-stable-stringify": "^2.0.0" + } + }, "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", @@ -832,6 +956,17 @@ "babel-template": "^6.24.1" } }, + "babel-literal-to-ast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/babel-literal-to-ast/-/babel-literal-to-ast-0.1.2.tgz", + "integrity": "sha1-9QqpY3EZNa3xnaDVpN78gnrV9AM=", + "dev": true, + "requires": { + "babel-traverse": "^6.0.20", + "babel-types": "^6.0.19", + "babylon": "^6.0.18" + } + }, "babel-loader": { "version": "7.1.4", "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-7.1.4.tgz", @@ -861,6 +996,29 @@ "babel-runtime": "^6.22.0" } }, + "babel-plugin-graphql-tag": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/babel-plugin-graphql-tag/-/babel-plugin-graphql-tag-1.6.0.tgz", + "integrity": "sha1-v9yD6ajQ7uptk1CNa1JhNoqmBk8=", + "dev": true, + "requires": { + "babel-literal-to-ast": "^0.1.2", + "babel-types": "^6.24.1", + "babylon": "^6.18.0", + "debug": "^2.6.8" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, "babel-plugin-syntax-async-functions": { "version": "6.13.0", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", @@ -1547,6 +1705,18 @@ } } }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + } + }, "babylon": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", @@ -3560,8 +3730,7 @@ "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", - "dev": true + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, "fastparse": { "version": "1.1.1", @@ -4735,6 +4904,27 @@ "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", "dev": true }, + "graphql": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-0.13.2.tgz", + "integrity": "sha512-QZ5BL8ZO/B20VA8APauGBg3GyEgZ19eduvpLWoq5x7gMmWnHoy8rlQWPLmWgFvo1yNgjSEFMesmS4R6pPr7xog==", + "requires": { + "iterall": "^1.2.1" + } + }, + "graphql-anywhere": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/graphql-anywhere/-/graphql-anywhere-4.1.13.tgz", + "integrity": "sha512-ef7NGkUBEwYeF+aQ/hdyfFgpvGGvkM+2FbW4403FKsi9coj91Bdfbmw9HHKbWxXsEUGYvW3+mYMIke0eIdgIJg==", + "requires": { + "apollo-utilities": "^1.0.15" + } + }, + "graphql-tag": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.9.2.tgz", + "integrity": "sha512-qnNmof9pAqj/LUzs3lStP0Gw1qhdVCUS7Ab7+SUB6KD5aX1uqxWQRwMnOGTkhKuLvLNIs1TvNz+iS9kUGl1MhA==" + }, "handle-thing": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-1.2.5.tgz", @@ -5569,6 +5759,11 @@ "whatwg-fetch": ">=0.10.0" } }, + "iterall": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.2.2.tgz", + "integrity": "sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA==" + }, "js-base64": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.3.tgz", @@ -8362,6 +8557,25 @@ "prop-types": "^15.6.0" } }, + "react-apollo": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/react-apollo/-/react-apollo-2.1.5.tgz", + "integrity": "sha512-ZJ+DaatsqTSV21FMNiHt5Gdwzlrj12labXkO0geLO0D5exeMgvY1adYYTLRUb6eM3+6fheGOIFv6mK5v3SopZg==", + "requires": { + "fbjs": "^0.8.16", + "hoist-non-react-statics": "^2.5.0", + "invariant": "^2.2.2", + "lodash": "4.17.10", + "prop-types": "^15.6.0" + }, + "dependencies": { + "lodash": { + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", + "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" + } + } + }, "react-dom": { "version": "16.3.2", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.3.2.tgz", @@ -9762,6 +9976,12 @@ "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", "dev": true }, + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true + }, "to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", @@ -10867,6 +11087,19 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", "dev": true + }, + "zen-observable": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.8.tgz", + "integrity": "sha512-HnhhyNnwTFzS48nihkCZIJGsWGFcYUz+XPDlPK5W84Ifji8SksC6m7sQWOf8zdCGhzQ4tDYuMYGu5B0N1dXTtg==" + }, + "zen-observable-ts": { + "version": "0.8.9", + "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-0.8.9.tgz", + "integrity": "sha512-KJz2O8FxbAdAU5CSc8qZ1K2WYEJb1HxS6XDRF+hOJ1rOYcg6eTMmS9xYHCXzqZZzKw6BbXWyF4UpwSsBQnHJeA==", + "requires": { + "zen-observable": "^0.8.0" + } } } } diff --git a/packages/venia-concept/package.json b/packages/venia-concept/package.json index 364905648cb..944655164a8 100644 --- a/packages/venia-concept/package.json +++ b/packages/venia-concept/package.json @@ -16,11 +16,15 @@ "start:debug": "node --inspect-brk ./node_modules/.bin/webpack-dev-server --progress --color --env.phase development" }, "dependencies": { - "@magento/peregrine": "^0.3.0", + "@magento/peregrine": "^0.4.0", + "apollo-boost": "^0.1.9", "babel-runtime": "^6.26.0", "dotenv": "^4.0.0", "feather-icons": "^4.6.0", + "graphql": "^0.13.2", + "graphql-tag": "^2.9.2", "react": "^16.2.0", + "react-apollo": "^2.1.5", "react-dom": "^16.2.0", "react-redux": "^5.0.6", "react-router-dom": "^4.2.2", @@ -30,6 +34,7 @@ "@magento/pwa-buildpack": "^0.8.2", "babel-core": "^6.26.0", "babel-loader": "^7.1.2", + "babel-plugin-graphql-tag": "^1.6.0", "babel-plugin-syntax-dynamic-import": "^6.18.0", "babel-plugin-syntax-jsx": "^6.18.0", "babel-plugin-transform-class-properties": "^6.24.1", diff --git a/packages/venia-concept/src/RootComponents/Category/category.js b/packages/venia-concept/src/RootComponents/Category/category.js index 0cf4b019a42..402de61aa87 100644 --- a/packages/venia-concept/src/RootComponents/Category/category.js +++ b/packages/venia-concept/src/RootComponents/Category/category.js @@ -1,51 +1,83 @@ import { Component, createElement } from 'react'; -import PropTypes from 'prop-types'; - +import { string, number, shape } from 'prop-types'; +import { Query } from 'react-apollo'; +import gql from 'graphql-tag'; import classify from 'src/classify'; import Gallery from 'src/components/Gallery'; import Page from 'src/components/Page'; -import mockData from './mockData'; import defaultClasses from './category.css'; -const emptyData = []; +const categoryQuery = gql` + query category($id: Int!) { + category(id: $id) { + description + name + product_count + products { + items { + id + name + small_image + price { + regularPrice { + amount { + value + currency + } + } + } + } + } + } + } +`; class Category extends Component { static propTypes = { - classes: PropTypes.shape({ - gallery: PropTypes.string, - root: PropTypes.string, - title: PropTypes.string + id: number, + classes: shape({ + gallery: string, + root: string, + title: string }) }; - state = { - loaded: false + // TODO: Should not be a default here, we just don't have + // the wiring in place to map route info down the tree (yet) + static defaultProps = { + id: 3 }; - componentDidMount() { - this.timer = window.setTimeout(() => { - this.setState(() => ({ loaded: true })); - }, 1000); - } - - componentWillUnmount() { - window.clearTimeout(this.timer); - } - render() { - const { classes } = this.props; - const data = this.state.loaded ? mockData : emptyData; + const { id, classes } = this.props; return ( -
-

- Dresses -

-
- -
-
+ + {({ loading, error, data }) => { + if (error) return
Data Fetch Error
; + if (loading) return
Fetching Data
; + + return ( +
+

+ {/* TODO: Switch to RichContent component from Peregrine when merged */} + +

+
+ +
+
+ ); + }} +
); } diff --git a/packages/venia-concept/src/RootComponents/Category/mockData.js b/packages/venia-concept/src/RootComponents/Category/mockData.js deleted file mode 100644 index 40fda8cda6d..00000000000 --- a/packages/venia-concept/src/RootComponents/Category/mockData.js +++ /dev/null @@ -1,66 +0,0 @@ -import * as images from './images'; - -const data = [ - { - key: '001', - name: 'Petra Sundress', - price: '$108' - }, - { - key: '002', - name: 'Athena Tank Dress', - price: '$128' - }, - { - key: '003', - name: 'Claudia Crochet Dress', - price: '$98' - }, - { - key: '004', - name: 'Alexia Maxi Dress', - price: '$78' - }, - { - key: '005', - name: 'Valentina Tank Dress', - price: '$78' - }, - { - key: '006', - name: 'Paulina Draped Tank Dress', - price: '$108' - }, - { - key: '007', - name: 'Flora Tank Dress', - price: '$148' - }, - { - key: '008', - name: 'Veronica Maxi Dress', - price: '$88' - }, - { - key: '009', - name: 'Felicia Maxi Dress', - price: '$128' - }, - { - key: '010', - name: 'Karena Halter Dress', - price: '$78' - }, - { - key: '011', - name: 'Candace Dress', - price: '$108' - }, - { - key: '012', - name: 'Angelina Tank Dress', - price: '$98' - } -].map(model => ({ ...model, image: images[`image${model.key}`] })); - -export default data; diff --git a/packages/venia-concept/src/components/Gallery/__tests__/gallery.spec.js b/packages/venia-concept/src/components/Gallery/__tests__/gallery.spec.js index cc54fd7e076..7ea8d483846 100644 --- a/packages/venia-concept/src/components/Gallery/__tests__/gallery.spec.js +++ b/packages/venia-concept/src/components/Gallery/__tests__/gallery.spec.js @@ -7,7 +7,34 @@ import Gallery from '../gallery'; configure({ adapter: new Adapter() }); const classes = { root: 'foo' }; -const items = [{ key: 'a' }, { key: 'b' }]; +const items = [ + { + id: 1, + name: 'Test Product 1', + small_image: '/test/product/1.png', + price: { + regularPrice: { + amount: { + value: 100, + currency: 'USD' + } + } + } + }, + { + id: 2, + name: 'Test Product 2', + small_image: '/test/product/2.png', + price: { + regularPrice: { + amount: { + value: 100, + currency: 'USD' + } + } + } + } +]; test('renders if `data` is an empty array', () => { const wrapper = shallow().dive(); diff --git a/packages/venia-concept/src/components/Gallery/__tests__/item.spec.js b/packages/venia-concept/src/components/Gallery/__tests__/item.spec.js index 69fc23b8825..e1c4e367171 100644 --- a/packages/venia-concept/src/components/Gallery/__tests__/item.spec.js +++ b/packages/venia-concept/src/components/Gallery/__tests__/item.spec.js @@ -22,10 +22,17 @@ const classes = { }; const validItem = { - key: 'foo', - image: 'foo.jpg', - name: 'Foo', - price: '$1.00' + id: 1, + name: 'Test Product', + small_image: '/foo/bar/pic.png', + price: { + regularPrice: { + amount: { + value: 21, + currency: 'USD' + } + } + } }; /** @@ -94,7 +101,7 @@ test('calls `onLoad` on image `load`', () => { .first() .simulate('load'); - expect(handleLoad).toBeCalledWith(validItem.key); + expect(handleLoad).toBeCalledWith(validItem.id); }); test('calls `onError` on image `error`', () => { @@ -113,7 +120,7 @@ test('calls `onError` on image `error`', () => { .first() .simulate('error'); - expect(handleError).toBeCalledWith(validItem.key); + expect(handleError).toBeCalledWith(validItem.id); }); /** diff --git a/packages/venia-concept/src/components/Gallery/__tests__/items.spec.js b/packages/venia-concept/src/components/Gallery/__tests__/items.spec.js index a7d6869cd26..c61474def95 100644 --- a/packages/venia-concept/src/components/Gallery/__tests__/items.spec.js +++ b/packages/venia-concept/src/components/Gallery/__tests__/items.spec.js @@ -6,8 +6,32 @@ import Items, { emptyData } from '../items'; configure({ adapter: new Adapter() }); -const items = [{ key: 'a' }, { key: 'b' }]; - +const items = [ + { + id: 1, + name: 'Test Product 1', + small_image: '/test/product/1.png', + price: { + regularPrice: { + amount: { + value: 100 + } + } + } + }, + { + id: 2, + name: 'Test Product 2', + small_image: '/test/product/2.png', + price: { + regularPrice: { + amount: { + value: 100 + } + } + } + } +]; // no render tests for now, since enzyme doesn't support React Fragment yet // see https://github.com/airbnb/enzyme/issues/1213 diff --git a/packages/venia-concept/src/components/Gallery/gallery.js b/packages/venia-concept/src/components/Gallery/gallery.js index 783badf6a5b..ace46efc7c0 100644 --- a/packages/venia-concept/src/components/Gallery/gallery.js +++ b/packages/venia-concept/src/components/Gallery/gallery.js @@ -1,20 +1,33 @@ import { Component, createElement } from 'react'; -import PropTypes from 'prop-types'; - +import { string, shape, arrayOf, number } from 'prop-types'; import classify from 'src/classify'; import GalleryItems, { emptyData } from './items'; import defaultClasses from './gallery.css'; class Gallery extends Component { static propTypes = { - classes: PropTypes.shape({ - actions: PropTypes.string, - filters: PropTypes.string, - items: PropTypes.string, - pagination: PropTypes.string, - root: PropTypes.string + classes: shape({ + actions: string, + filters: string, + items: string, + pagination: string, + root: string }), - data: PropTypes.arrayOf(PropTypes.object) + data: arrayOf( + shape({ + id: number.isRequired, + name: string.isRequired, + small_image: string.isRequired, + price: shape({ + regularPrice: shape({ + amount: shape({ + value: number.isRequired, + currency: string.isRequired + }).isRequired + }).isRequired + }).isRequired + }) + ) }; static defaultProps = { diff --git a/packages/venia-concept/src/components/Gallery/item.js b/packages/venia-concept/src/components/Gallery/item.js index 486a8fcf5c0..d8ed324c115 100644 --- a/packages/venia-concept/src/components/Gallery/item.js +++ b/packages/venia-concept/src/components/Gallery/item.js @@ -1,6 +1,6 @@ import { Component, createElement } from 'react'; -import PropTypes from 'prop-types'; - +import { string, number, shape, func, bool } from 'prop-types'; +import { Price } from '@magento/peregrine'; import classify from 'src/classify'; import { imagePlaceholderUri } from 'src/constants'; import defaultClasses from './item.css'; @@ -18,29 +18,36 @@ const ItemPlaceholder = ({ children, classes }) => ( class GalleryItem extends Component { static propTypes = { - classes: PropTypes.shape({ - image: PropTypes.string, - image_pending: PropTypes.string, - imagePlaceholder: PropTypes.string, - imagePlaceholder_pending: PropTypes.string, - images: PropTypes.string, - images_pending: PropTypes.string, - name: PropTypes.string, - name_pending: PropTypes.string, - price: PropTypes.string, - price_pending: PropTypes.string, - root: PropTypes.string, - root_pending: PropTypes.string + classes: shape({ + image: string, + image_pending: string, + imagePlaceholder: string, + imagePlaceholder_pending: string, + images: string, + images_pending: string, + name: string, + name_pending: string, + price: string, + price_pending: string, + root: string, + root_pending: string }), - item: PropTypes.shape({ - key: PropTypes.string.isRequired, - image: PropTypes.string, - name: PropTypes.string, - price: PropTypes.string + item: shape({ + id: number.isRequired, + name: string.isRequired, + small_image: string.isRequired, + price: shape({ + regularPrice: shape({ + amount: shape({ + value: number.isRequired, + currency: string.isRequired + }).isRequired + }).isRequired + }).isRequired }), - onError: PropTypes.func, - onLoad: PropTypes.func, - showImage: PropTypes.bool + onError: func, + onLoad: func, + showImage: bool }; static defaultProps = { @@ -71,7 +78,10 @@ class GalleryItem extends Component { {name}
- {price} +
); @@ -99,6 +109,10 @@ class GalleryItem extends Component { ); }; + /** + * Product images are currently broken and pending a fix from the `graphql-ce` project + * https://github.com/magento/graphql-ce/issues/88 + */ renderImage = () => { const { classes, item, showImage } = this.props; @@ -106,13 +120,13 @@ class GalleryItem extends Component { return null; } - const { image, name } = item; + const { small_image, name } = item; const className = showImage ? classes.image : classes.image_pending; return ( {name} { const { item, onLoad } = this.props; - onLoad(item.key); + onLoad(item.id); }; handleError = () => { const { item, onError } = this.props; - onError(item.key); + onError(item.id); }; } diff --git a/packages/venia-concept/src/components/Gallery/items.js b/packages/venia-concept/src/components/Gallery/items.js index 6955cd5b3ca..c9ed68ea981 100644 --- a/packages/venia-concept/src/components/Gallery/items.js +++ b/packages/venia-concept/src/components/Gallery/items.js @@ -1,6 +1,5 @@ import { Component, createElement } from 'react'; -import PropTypes from 'prop-types'; - +import { arrayOf, string, number, shape } from 'prop-types'; import fixedObserver from 'src/util/fixedObserver'; import initObserver from 'src/util/initObserver'; import GalleryItem from './item'; @@ -23,7 +22,20 @@ const initState = (prevState, { items }) => ({ class GalleryItems extends Component { static propTypes = { - items: PropTypes.arrayOf(PropTypes.object).isRequired + items: arrayOf( + shape({ + id: number.isRequired, + name: string.isRequired, + small_image: string.isRequired, + price: shape({ + regularPrice: shape({ + amount: shape({ + value: number.isRequired + }).isRequired + }).isRequired + }).isRequired + }) + ).isRequired }; constructor(props) { @@ -53,7 +65,7 @@ class GalleryItems extends Component { return items.map(item => ( , document.getElementById('root')); +const apolloClient = new ApolloClient(); + +ReactDOM.render( + + + , + document.getElementById('root') +); if (process.env.SERVICE_WORKER && 'serviceWorker' in navigator) { window.addEventListener('load', () => {