: 'identity-obj-proxy',\n },\n transform: {\n '^.+\\\\.stories\\\\.jsx?
: '@storybook\u002Faddon-storyshots\u002FinjectFileName',\n '^.+\\\\.jsx?
: 'babel-jest',\n },\n}\n","id":"mod_C5AaHmkVMmjYEnMV33RTEM","is_binary":false,"title":"jest.config.js","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"S1PzWQICsE8","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"rkj-QI0jEI"},{"code":"https:\u002F\u002Frawcdn.githack.com\u002FJimmyLv\u002Ftdd-commentbox\u002F84abb95cd9108b7e326339c93c6fad59370d4de9\u002Ftests\u002Fsnapshots\u002F__image_snapshots__\u002Fstoryshots-spec-js-image-storyshots-category-tabs-category-tabs-1-snap.png","id":"mod_Eixe8HGVCUYBngaHPaeMav","is_binary":true,"title":"storyshots-spec-js-image-storyshots-category-tabs-category-tabs-1-snap.png","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"Sk_z-7URjEI","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"rypWmICjNL"},{"code":"https:\u002F\u002Frawcdn.githack.com\u002FJimmyLv\u002Ftdd-commentbox\u002F84abb95cd9108b7e326339c93c6fad59370d4de9\u002Ftests\u002Fsnapshots\u002F__image_snapshots__\u002Fstoryshots-spec-js-image-storyshots-tag-list-tag-list-1-snap.png","id":"mod_PUf6JMXoHBuEZariMymtWZ","is_binary":true,"title":"storyshots-spec-js-image-storyshots-tag-list-tag-list-1-snap.png","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"ryFz-mI0iV8","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"rypWmICjNL"},{"code":"import initStoryshots from '@storybook\u002Faddon-storyshots'\nimport { imageSnapshot } from '@storybook\u002Faddon-storyshots-puppeteer'\n\nconst getScreenshotOptions = ({ context, url }) =\u003E {\n return {\n fullPage: false, \u002F\u002F Do not take the full page screenshot. Default is 'true' in Storyshots.\n }\n}\n\nconst beforeScreenshot = (page, { context: { kind, story }, url }) =\u003E {\n page.setViewport({ width: 1440, height: 960 })\n}\n\ninitStoryshots({\n suite: 'Image storyshots',\n test: imageSnapshot({\n storybookUrl: 'http:\u002F\u002Flocalhost:6006',\n getScreenshotOptions,\n beforeScreenshot,\n }),\n})\n","id":"mod_5neTymzRFLPoBp8aG8cwvZ","is_binary":false,"title":"storyshots.spec.js","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"HkcMb7LAiNI","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"ryh-mLCs4L"},{"code":"https:\u002F\u002Frawcdn.githack.com\u002FJimmyLv\u002Ftdd-commentbox\u002F84abb95cd9108b7e326339c93c6fad59370d4de9\u002Ftests\u002Fsnapshots\u002F__image_snapshots__\u002Fstoryshots-spec-js-image-storyshots-book-item-simple-book-1-snap.png","id":"mod_YKpvrUbgHSQTLNuuENU3rZ","is_binary":true,"title":"storyshots-spec-js-image-storyshots-book-item-simple-book-1-snap.png","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"HyoG-XLRiNU","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"rypWmICjNL"},{"code":"https:\u002F\u002Frawcdn.githack.com\u002FJimmyLv\u002Ftdd-commentbox\u002F84abb95cd9108b7e326339c93c6fad59370d4de9\u002Fyarn.lock","id":"mod_Jx6NhFnYfDPNrCdJDbsHmk","is_binary":true,"title":"yarn.lock","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"HJ3zWQ8Co48","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":null},{"code":"function addComment(commentText) {\n cy.queryByPlaceholderText('请输入新留言…').type(commentText)\n cy.queryByTestId('reply-comment').click()\n}\n\ndescribe('Comments Page', () =\u003E {\n it('should add new comment and show comment list', () =\u003E {\n const commentText = '唱跳Rap篮球!!!'\n const repliedComment = '律师函警告!'\n\n cy.visit('\u002F')\n cy.queryByTestId('comment-title').should('have.text', '留言板')\n cy.queryByText('留言为空').should('exist')\n\n addComment(commentText)\n\n cy.queryByTestId('comment-title').should('have.text', '1 留言')\n cy.queryByText('留言为空').should('not.exist')\n cy.queryByText(commentText).should('be.visible')\n\n addComment(repliedComment)\n\n cy.queryByTestId('comment-title').should('have.text', '2 留言')\n cy.queryAllByTestId('comment-content')\n .eq(0)\n .should('have.text', repliedComment)\n cy.queryAllByTestId('comment-content')\n .eq(1)\n .should('have.text', commentText)\n\n cy.queryByTestId('sort-comment').click()\n cy.queryByText('从旧到新').click()\n cy.queryAllByTestId('comment-content')\n .eq(0)\n .should('have.text', commentText)\n })\n})\n","id":"mod_P9uCCqFZAcBa7TN3CbEBCb","is_binary":false,"title":"Comments.test.js","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"Bk8x-XUCiNU","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"ryQZQLCs48"},{"code":"https:\u002F\u002Frawcdn.githack.com\u002FJimmyLv\u002Ftdd-commentbox\u002F84abb95cd9108b7e326339c93c6fad59370d4de9\u002Fcypress\u002Fintegration\u002FE2E\u002FComments.todo","id":"mod_XkCAsXHc1ivEdkRvJwayyz","is_binary":true,"title":"Comments.todo","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"r1vxb7I0oEL","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"ryQZQLCs48"},{"code":"Feature: The Bing\n\n I want to open a social network page\n\n @focus\n Scenario: Opening a social network page\n Given I open \"https:\u002F\u002Fbing.com\" page\n Then I see \"Bing\" in the title\n","id":"mod_Q6Ud6KkK5oSa36SUFu2pDT","is_binary":false,"title":"Search.feature","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"B1_g-XLRoVL","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"ryQZQLCs48"},{"code":"import { Given, Then } from 'cypress-cucumber-preprocessor\u002Fsteps'\n\nGiven('I open {string} page', (url) =\u003E {\n cy.visit(url)\n})\n\nThen(`I see {string} in the title`, (title) =\u003E {\n cy.title().should('include', title)\n})\n","id":"mod_B3pVNg8zvGe6gp85R5ANh6","is_binary":false,"title":"E2E.step.js","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"BJFl-QIRjE8","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"rk4-780iEI"},{"code":"import { action } from '@storybook\u002Faddon-actions'\n\nlet act\nif (typeof Cypress !== 'undefined') {\n act = name =\u003E cy.spy().as(name)\n} else {\n act = action\n}\n\nexport default act\n","id":"mod_75XUSA6Ha1unm3HkAPbdtG","is_binary":false,"title":"action.js","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"Byqgb7URiE8","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"rk4-780iEI"},{"code":"\u002F\u002F ***********************************************************\n\u002F\u002F This example plugins\u002Findex.js can be used to load plugins\n\u002F\u002F\n\u002F\u002F You can change the location of this file or turn off loading\n\u002F\u002F the plugins file with the 'pluginsFile' configuration option.\n\u002F\u002F\n\u002F\u002F You can read more here:\n\u002F\u002F https:\u002F\u002Fon.cypress.io\u002Fplugins-guide\n\u002F\u002F ***********************************************************\n\n\u002F\u002F This function is called when a project is opened or re-opened (e.g. due to\n\u002F\u002F the project's config changing)\nconst { addMatchImageSnapshotPlugin } = require('cypress-image-snapshot\u002Fplugin')\nconst cucumber = require('cypress-cucumber-preprocessor').default\n\nmodule.exports = (on, config) =\u003E {\n \u002F\u002F `on` is used to hook into various events Cypress emits\n \u002F\u002F `config` is the resolved Cypress config\n addMatchImageSnapshotPlugin(on, config)\n on('file:preprocessor', cucumber())\n return config\n}\n","id":"mod_SaF6ZMwgJZDQmjB3RqQKqS","is_binary":false,"title":"index.js","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"Skog-Q80jEU","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"S1Sb7I0jN8"},{"code":"\u002F\u002F ***********************************************\n\u002F\u002F This example commands.js shows you how to\n\u002F\u002F create various custom commands and overwrite\n\u002F\u002F existing commands.\n\u002F\u002F\n\u002F\u002F For more comprehensive examples of custom\n\u002F\u002F commands please read more here:\n\u002F\u002F https:\u002F\u002Fon.cypress.io\u002Fcustom-commands\n\u002F\u002F ***********************************************\n\u002F\u002F\n\u002F\u002F\n\u002F\u002F -- This is a parent command --\n\u002F\u002F Cypress.Commands.add(\"login\", (email, password) =\u003E { ... })\n\u002F\u002F\n\u002F\u002F\n\u002F\u002F -- This is a child command --\n\u002F\u002F Cypress.Commands.add(\"drag\", { prevSubject: 'element'}, (subject, options) =\u003E { ... })\n\u002F\u002F\n\u002F\u002F\n\u002F\u002F -- This is a dual command --\n\u002F\u002F Cypress.Commands.add(\"dismiss\", { prevSubject: 'optional'}, (subject, options) =\u003E { ... })\n\u002F\u002F\n\u002F\u002F\n\u002F\u002F -- This will overwrite an existing command --\n\u002F\u002F Cypress.Commands.overwrite(\"visit\", (originalFn, url, options) =\u003E { ... })\n\nimport '@testing-library\u002Fcypress\u002Fadd-commands'\nimport { addMatchImageSnapshotCommand } from 'cypress-image-snapshot\u002Fcommand'\n\naddMatchImageSnapshotCommand({\n failureThreshold: 0.0,\n failureThresholdType: 'percent',\n customDiffConfig: { threshold: 0.0 },\n capture: 'fullPage',\n})\n\nCypress.Commands.add('setResolution', size =\u003E {\n if (Cypress._.isArray(size)) {\n cy.viewport(size[0], size[1])\n } else {\n cy.viewport(size)\n }\n})\n","id":"mod_Vq9uPUrA3jYqrJK3ihHEoA","is_binary":false,"title":"commands.js","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"HkhlbXURo4U","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"Hy8-QL0oEU"},{"code":"\u002F\u002F ***********************************************************\n\u002F\u002F This example support\u002Findex.js is processed and\n\u002F\u002F loaded automatically before your test files.\n\u002F\u002F\n\u002F\u002F This is a great place to put global configuration and\n\u002F\u002F behavior that modifies Cypress.\n\u002F\u002F\n\u002F\u002F You can change the location of this file or turn off\n\u002F\u002F automatically serving support files with the\n\u002F\u002F 'supportFile' configuration option.\n\u002F\u002F\n\u002F\u002F You can read more here:\n\u002F\u002F https:\u002F\u002Fon.cypress.io\u002Fconfiguration\n\u002F\u002F ***********************************************************\n\n\u002F\u002F Import commands.js using ES2015 syntax:\nimport '.\u002Fcommands';\n\u002F\u002F Alternatively you can use CommonJS syntax:\n\u002F\u002F require('.\u002Fcommands')\n","id":"mod_9oB1dbqGkKayL5zFcW5N18","is_binary":false,"title":"index.js","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"Sype-78CsNU","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"Hy8-QL0oEU"},{"code":"export default {\n '\u002Fapi\u002Fbooks': [\n {\n id: 1,\n name: '你不知道的JavaScript',\n author: 'Kyle',\n region: '美国',\n cover:\n 'http:\u002F\u002Fcover.read.duokan.com\u002Fmfsv2\u002Fdownload\u002Fs010\u002Fp01g8NOQ3Elv\u002Fazwcob3UZrT7X6.jpg!e',\n category: '编程',\n tags: ['JavaScript', 'Web'],\n },\n\n {\n id: 2,\n name: 'Java编程思想(第4版)',\n author: '埃史尔',\n region: '美国',\n cover: 'https:\u002F\u002Fwww.linuxidc.com\u002Fupload\u002F2014_08\u002F140811101915661.jpg',\n category: '编程',\n tags: ['Java', 'Web'],\n },\n\n {\n id: 3,\n name: '你不知道的React',\n author: 'JimmyLv',\n region: '中国',\n cover:\n 'http:\u002F\u002Fcover.read.duokan.com\u002Fmfsv2\u002Fdownload\u002Fs010\u002Fp01g8NOQ3Elv\u002Fazwcob3UZrT7X6.jpg!e',\n category: '前端',\n tags: ['Web', 'React'],\n },\n {\n id: 3,\n name: '平凡的世界',\n author: '路遥',\n region: '中国',\n cover:\n 'http:\u002F\u002Fcover.read.duokan.com\u002Fmfsv2\u002Fdownload\u002Fs010\u002Fp01g8NOQ3Elv\u002Fazwcob3UZrT7X6.jpg!e',\n category: '文学',\n tags: ['当代', '社会'],\n },\n {\n id: 4,\n name: '国富论',\n author: '亚当·斯密',\n region: '英国',\n cover:\n 'https:\u002F\u002Fwiki.mbalib.com\u002Fw\u002Fimages\u002Fthumb\u002F3\u002F38\u002F%E5%9B%BD%E5%AF%8C%E8%AE%BA.jpg\u002F190px-%E5%9B%BD%E5%AF%8C%E8%AE%BA.jpg',\n category: '经济',\n tags: ['经济', '社会'],\n },\n ],\n}\n","id":"mod_W9PqD8Dt4PfJ9QCBURKa7k","is_binary":false,"title":"book.js","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"H10e-Q8As48","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"rkv-QL0j4U"},{"code":"{\n \"todos\": [\n {\n \"id\": 1,\n \"text\": \"read something\",\n \"completed\": false\n },\n {\n \"id\": 2,\n \"text\": \"write something\",\n \"completed\": true\n }\n ],\n \"comments\": [\n {\n \"id\": 1,\n \"body\": \"some comment\",\n \"postId\": 1\n }\n ],\n \"profile\": {\n \"name\": \"typicode\"\n },\n \"books\": [\n {\n \"id\": 1,\n \"name\": \"你不知道的JavaScript\",\n \"author\": \"Kyle\",\n \"region\": \"美国\",\n \"cover\": \"http:\u002F\u002Fcover.read.duokan.com\u002Fmfsv2\u002Fdownload\u002Fs010\u002Fp01g8NOQ3Elv\u002Fazwcob3UZrT7X6.jpg!e\",\n \"category\": \"编程\",\n \"tags\": [\"JavaScript\", \"Web\"]\n },\n\n {\n \"id\": 2,\n \"name\": \"Java编程思想(第4版)\",\n \"author\": \"埃史尔\",\n \"region\": \"美国\",\n \"cover\": \"https:\u002F\u002Fwww.linuxidc.com\u002Fupload\u002F2014_08\u002F140811101915661.jpg\",\n \"category\": \"编程\",\n \"tags\": [\"Java\", \"Web\"]\n },\n\n {\n \"id\": 3,\n \"name\": \"你不知道的React\",\n \"author\": \"JimmyLv\",\n \"region\": \"中国\",\n \"cover\": \"http:\u002F\u002Fcover.read.duokan.com\u002Fmfsv2\u002Fdownload\u002Fs010\u002Fp01g8NOQ3Elv\u002Fazwcob3UZrT7X6.jpg!e\",\n \"category\": \"前端\",\n \"tags\": [\"Web\", \"React\"]\n },\n {\n \"id\": 3,\n \"name\": \"平凡的世界\",\n \"author\": \"路遥\",\n \"region\": \"中国\",\n \"cover\": \"http:\u002F\u002Fcover.read.duokan.com\u002Fmfsv2\u002Fdownload\u002Fs010\u002Fp01g8NOQ3Elv\u002Fazwcob3UZrT7X6.jpg!e\",\n \"category\": \"文学\",\n \"tags\": [\"当代\", \"社会\"]\n },\n {\n \"id\": 4,\n \"name\": \"国富论\",\n \"author\": \"亚当·斯密\",\n \"region\": \"英国\",\n \"cover\": \"https:\u002F\u002Fwiki.mbalib.com\u002Fw\u002Fimages\u002Fthumb\u002F3\u002F38\u002F%E5%9B%BD%E5%AF%8C%E8%AE%BA.jpg\u002F190px-%E5%9B%BD%E5%AF%8C%E8%AE%BA.jpg\",\n \"category\": \"经济\",\n \"tags\": [\"经济\", \"社会\"]\n }\n ]\n}\n","id":"mod_6ReqgkyTGTC6oejcu8JFTa","is_binary":false,"title":"db.json","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"BkJbbX8CjV8","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"rkv-QL0j4U"},{"code":"{\n \"\u002Fapi\u002F*\": \"\u002F$1\"\n}\n","id":"mod_C9F17fE9gdENeDJKRkQoCn","is_binary":false,"title":"routes.json","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"BkgZZQ8As48","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"rkv-QL0j4U"},{"code":"{\n \"name\": \"tdd-commentbox\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"scripts\": {\n \"start\": \"react-app-rewired start\",\n \"build\": \"react-app-rewired build\",\n \"test\": \"react-app-rewired test\",\n \"test:ci\": \"cross-env CI=true yarn test --coverage\",\n \"test:story\": \"jest test \u002Ftests --testMatch '**\u002F*.spec.js' --config tests\u002Fjest.config.js\",\n \"test:story:update\": \"yarn test:story -u\",\n \"lint:fix\": \"eslint src --fix\",\n \"cy:open\": \"cypress open\",\n \"cy:e2e\": \"cypress run\",\n \"cy:e2e:update\": \"yarn cy:e2e --env updateSnapshots=true\",\n \"mock\": \"json-server --watch mock\u002Fdb.json --routes mock\u002Froutes.json --port 8080\",\n \"storybook\": \"start-storybook -p 6006 -s public\",\n \"build-storybook\": \"build-storybook -s public\"\n },\n \"proxy\": \"http:\u002F\u002Flocalhost:8080\",\n \"dependencies\": {\n \"@storybook\u002Faddon-actions\": \"^5.3.7\",\n \"@storybook\u002Faddon-links\": \"^5.3.7\",\n \"@storybook\u002Faddon-storyshots\": \"^5.3.8\",\n \"@storybook\u002Faddon-storyshots-puppeteer\": \"^5.3.8\",\n \"@storybook\u002Faddons\": \"^5.3.7\",\n \"@storybook\u002Freact\": \"^5.3.7\",\n \"@testing-library\u002Fcypress\": \"^5.0.2\",\n \"@testing-library\u002Fjest-dom\": \"^4.2.4\",\n \"@testing-library\u002Freact\": \"^9.3.2\",\n \"@testing-library\u002Fuser-event\": \"^7.1.2\",\n \"antd\": \"^3.25.3\",\n \"lodash\": \"^4.17.15\",\n \"react\": \"^16.12.0\",\n \"react-dom\": \"^16.12.0\",\n \"react-redux\": \"^7.1.3\",\n \"react-router-dom\": \"^5.1.2\",\n \"react-scripts\": \"3.3.0\",\n \"redux\": \"^4.0.5\",\n \"redux-devtools-extension\": \"^2.13.8\",\n \"redux-saga\": \"^1.1.3\",\n \"redux-thunk\": \"^2.3.0\",\n \"reselect\": \"^4.0.0\",\n \"styled-components\": \"^5.0.0\"\n },\n \"devDependencies\": {\n \"babel-plugin-import\": \"^1.12.2\",\n \"cross-env\": \"^7.0.0\",\n \"customize-cra\": \"^0.9.1\",\n \"cypress\": \"^3.8.2\",\n \"cypress-cucumber-preprocessor\": \"^2.0.1\",\n \"cypress-image-snapshot\": \"^3.1.1\",\n \"eslint-plugin-prettier\": \"^3.1.1\",\n \"husky\": \"^4.2.1\",\n \"json-server\": \"^0.15.1\",\n \"less\": \"^3.10.3\",\n \"less-loader\": \"^5.0.0\",\n \"lint-staged\": \"^10.0.2\",\n \"prettier\": \"^1.19.1\",\n \"puppeteer\": \"^2.1.0\",\n \"react-app-rewired\": \"^2.1.5\",\n \"react-test-renderer\": \"^16.12.0\",\n \"redux-mock-store\": \"^1.5.3\",\n \"redux-saga-test-plan\": \"^4.0.0-rc.2\",\n \"storybook-react-router\": \"^1.0.8\"\n },\n \"babel\": {\n \"presets\": [\n \"@babel\u002Fpreset-env\",\n \"@babel\u002Fpreset-react\"\n ]\n },\n \"eslintConfig\": {\n \"extends\": \"react-app\",\n \"plugins\": [\n \"prettier\"\n ],\n \"rules\": {\n \"prettier\u002Fprettier\": \"error\",\n \"jsx-a11y\u002Faccessible-emoji\": \"off\"\n },\n \"globals\": {\n \"Cypress\": true,\n \"cy\": true\n }\n },\n \"prettier\": {\n \"singleQuote\": true,\n \"trailingComma\": \"es5\",\n \"semi\": false\n },\n \"lint-staged\": {\n \"*.{js}\": [\n \"prettier --write\",\n \"eslint --fix\",\n \"git add\"\n ]\n },\n \"husky\": {\n \"hooks\": {\n \"post-commit\": \"git update-index --again\",\n \"pre-commit\": \"lint-staged\",\n \"pre-push\": \"yarn test:ci\"\n }\n },\n \"browserslist\": {\n \"production\": [\n \"\u003E0.2%\",\n \"not dead\",\n \"not op_mini all\"\n ],\n \"development\": [\n \"last 1 chrome version\",\n \"last 1 firefox version\",\n \"last 1 safari version\"\n ]\n }\n}\n","id":"mod_DpRBWQTPvRzUuooQPsDYfu","is_binary":false,"title":"package.json","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"SJWZ-78AsNL","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":null},{"code":"https:\u002F\u002Frawcdn.githack.com\u002FJimmyLv\u002Ftdd-commentbox\u002F84abb95cd9108b7e326339c93c6fad59370d4de9\u002Fpublic\u002Ffavicon.ico","id":"mod_6rBJ9y2ycBqMzRUMjWaT6Z","is_binary":true,"title":"favicon.ico","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"HkzWZmU0oV8","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"rJOWmLAj48"},{"code":"\u002F\u002F @ts-nocheck\nimport React, { useState } from 'react'\nimport styled from 'styled-components'\nimport { AddComment } from '.\u002FAddComment'\nimport { CommentList } from '.\u002FCommentList'\nimport { CommentTitle } from '.\u002FCommentTitle'\n\nexport function CommentBox() {\n const [comments, setComments] = useState([])\n const [sortType, setSortType] = useState('latest')\n return (\n \u003CStyledBox\u003E\n \u003CCommentTitle comments={comments} onSort={type =\u003E setSortType(type)} \u002F\u003E\n\n \u003CAddComment onSave={comment =\u003E setComments([...comments, comment])} \u002F\u003E\n\n \u003CCommentList comments={comments} sortType={sortType} \u002F\u003E\n \u003C\u002FStyledBox\u003E\n )\n}\n\nconst StyledBox = styled.div`\n margin: 20px;\n`\n","id":"mod_VvL8VnkU1mymABWFhxiXeb","is_binary":false,"title":"CommentBox.js","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"BJnbbmICjEI","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"B1c-X80jE8"},{"code":"\u003C!DOCTYPE html\u003E\n\u003Chtml lang=\"en\"\u003E\n \u003Chead\u003E\n \u003Cmeta charset=\"utf-8\" \u002F\u003E\n \u003Clink rel=\"shortcut icon\" href=\"%PUBLIC_URL%\u002Ffavicon.ico\" \u002F\u003E\n \u003Cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1\" \u002F\u003E\n \u003Cmeta name=\"theme-color\" content=\"#000000\" \u002F\u003E\n \u003Cmeta\n name=\"description\"\n content=\"Web site created using create-react-app\"\n \u002F\u003E\n \u003Clink rel=\"apple-touch-icon\" href=\"%PUBLIC_URL%\u002Flogo192.png\" \u002F\u003E\n \u003C!--\n manifest.json provides metadata used when your web app is installed on a\n user's mobile device or desktop. See https:\u002F\u002Fdevelopers.google.com\u002Fweb\u002Ffundamentals\u002Fweb-app-manifest\u002F\n --\u003E\n \u003Clink rel=\"manifest\" href=\"%PUBLIC_URL%\u002Fmanifest.json\" \u002F\u003E\n \u003C!--\n Notice the use of %PUBLIC_URL% in the tags above.\n It will be replaced with the URL of the `public` folder during the build.\n Only files inside the `public` folder can be referenced from the HTML.\n\n Unlike \"\u002Ffavicon.ico\" or \"favicon.ico\", \"%PUBLIC_URL%\u002Ffavicon.ico\" will\n work correctly both with client-side routing and a non-root public URL.\n Learn how to configure a non-root public URL by running `npm run build`.\n --\u003E\n \u003Ctitle\u003ETDD CommentBox\u003C\u002Ftitle\u003E\n \u003C\u002Fhead\u003E\n \u003Cbody\u003E\n \u003Cnoscript\u003EYou need to enable JavaScript to run this app.\u003C\u002Fnoscript\u003E\n \u003Cdiv id=\"root\"\u003E\u003C\u002Fdiv\u003E\n \u003C!--\n This HTML file is a template.\n If you open it directly in the browser, you will see an empty page.\n\n You can add webfonts, meta tags, or analytics to this file.\n The build step will place the bundled scripts into the \u003Cbody\u003E tag.\n\n To begin the development, run `npm start` or `yarn start`.\n To create a production bundle, use `npm run build` or `yarn build`.\n --\u003E\n \u003C\u002Fbody\u003E\n\u003C\u002Fhtml\u003E\n","id":"mod_Q3YcVHUW2a3uDo1h7bdACQ","is_binary":false,"title":"index.html","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"H17b-QURoNU","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"rJOWmLAj48"},{"code":"https:\u002F\u002Frawcdn.githack.com\u002FJimmyLv\u002Ftdd-commentbox\u002F84abb95cd9108b7e326339c93c6fad59370d4de9\u002Fpublic\u002Flogo192.png","id":"mod_Wik6jdFx2CnZB4CD5MqjBM","is_binary":true,"title":"logo192.png","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"rJNbWmICjNL","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"rJOWmLAj48"},{"code":"https:\u002F\u002Frawcdn.githack.com\u002FJimmyLv\u002Ftdd-commentbox\u002F84abb95cd9108b7e326339c93c6fad59370d4de9\u002Fpublic\u002Flogo512.png","id":"mod_3xLF5eFMzVdhPvdEtDYadq","is_binary":true,"title":"logo512.png","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"S1SWWXLRj4U","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"rJOWmLAj48"},{"code":"{\n \"short_name\": \"React App\",\n \"name\": \"Create React App Sample\",\n \"icons\": [\n {\n \"src\": \"favicon.ico\",\n \"sizes\": \"64x64 32x32 24x24 16x16\",\n \"type\": \"image\u002Fx-icon\"\n },\n {\n \"src\": \"logo192.png\",\n \"type\": \"image\u002Fpng\",\n \"sizes\": \"192x192\"\n },\n {\n \"src\": \"logo512.png\",\n \"type\": \"image\u002Fpng\",\n \"sizes\": \"512x512\"\n }\n ],\n \"start_url\": \".\",\n \"display\": \"standalone\",\n \"theme_color\": \"#000000\",\n \"background_color\": \"#ffffff\"\n}\n","id":"mod_HiHy64xLzVbUotZnsJUfsx","is_binary":false,"title":"manifest.json","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"rJLb-QI0oN8","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"rJOWmLAj48"},{"code":"# https:\u002F\u002Fwww.robotstxt.org\u002Frobotstxt.html\nUser-agent: *\n","id":"mod_6MbsFLLT2NdpMT4x1um1Zo","is_binary":false,"title":"robots.txt","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"B1P-bmIAoNU","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"rJOWmLAj48"},{"code":"import 'antd\u002Fdist\u002Fantd.css'\nimport React from 'react'\nimport { CommentBox } from '.\u002Fcomponents\u002FCommentBox'\n\nfunction App() {\n return (\n \u003C\u003E\n \u003Ch1 data-testid=\"title\"\u003E练功房前端脚手架\u003C\u002Fh1\u003E\n \u003CCommentBox \u002F\u003E\n \u003C\u002F\u003E\n )\n}\n\nexport default App\n","id":"mod_99PXkUHeMw4MCb5mYjweoB","is_binary":false,"title":"App.js","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"rJdZZ7U0iVU","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"ryYbX8Co48"},{"code":"import { Button, Input } from 'antd'\nimport React, { useState } from 'react'\nimport styled from 'styled-components'\n\nexport function AddComment({ onSave }) {\n const [comment, setComment] = useState('')\n const [showButton, setShowButton] = useState(false)\n\n function addNewComment() {\n onSave(comment)\n setComment('')\n setShowButton(false)\n }\n\n return (\n \u003CStyledBox\u003E\n \u003CInput\n type=\"text\"\n placeholder=\"请输入新留言…\"\n value={comment}\n onChange={e =\u003E setComment(e.target.value)}\n onClick={() =\u003E setShowButton(true)}\n onPressEnter={addNewComment}\n \u002F\u003E\n {showButton && (\n \u003Cdiv\u003E\n \u003CButton\n data-testid=\"cancel-comment\"\n onClick={() =\u003E setShowButton(false)}\n \u003E\n 取消\n \u003C\u002FButton\u003E\n \u003CButton\n data-testid=\"reply-comment\"\n type=\"primary\"\n onClick={addNewComment}\n \u003E\n 回复\n \u003C\u002FButton\u003E\n \u003C\u002Fdiv\u003E\n )}\n \u003C\u002FStyledBox\u003E\n )\n}\n\nconst StyledBox = styled.div`\n display: flex;\n align-items: center;\n justify-content: space-between;\n\n input {\n width: 80%;\n }\n`\n","id":"mod_8BnSa8EhLVJwV9YnQfAF5K","is_binary":false,"title":"AddComment.js","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"SJFZZXLCj4L","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"B1c-X80jE8"},{"code":"import { action } from '@storybook\u002Faddon-actions'\nimport React from 'react'\nimport { AddComment } from '.\u002FAddComment'\n\nexport default {\n title: 'AddComment',\n}\n\nexport const add = () =\u003E \u003CAddComment onSave={action('saveHandler')} \u002F\u003E\n","id":"mod_CHsQg7YP6sDscW7FkfB1jc","is_binary":false,"title":"AddComment.stories.js","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"By5-bmLRjEI","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"B1c-X80jE8"},{"code":"import userEvent from '@testing-library\u002Fuser-event'\nimport React from 'react'\nimport { AddComment } from '.\u002FAddComment'\nimport { fireEvent, render } from '@testing-library\u002Freact'\n\nconst commentText = 'newComment'\n\nit('should call onSave when add new comment', () =\u003E {\n let saveHandler = jest.fn()\n\n const { queryByPlaceholderText, queryByTestId } = render(\n \u003CAddComment onSave={saveHandler} \u002F\u003E\n )\n\n userEvent.click(queryByPlaceholderText('请输入新留言…'))\n userEvent.type(queryByPlaceholderText('请输入新留言…'), commentText)\n userEvent.click(queryByTestId('reply-comment'))\n\n expect(saveHandler).toBeCalledWith(commentText)\n expect(queryByPlaceholderText('请输入新留言…').value).toBe('')\n expect(queryByTestId('reply-comment')).toBe(null)\n})\n\nit('should only show button when click input', () =\u003E {\n const { queryByPlaceholderText, queryByTestId } = render(\u003CAddComment \u002F\u003E)\n\n expect(queryByTestId('reply-comment')).toBe(null)\n\n userEvent.click(queryByPlaceholderText('请输入新留言…'))\n expect(queryByTestId('reply-comment')).toHaveTextContent('回 复')\n\n userEvent.click(queryByTestId('cancel-comment'))\n expect(queryByTestId('reply-comment')).toBe(null)\n})\n\nit.skip('should save comment when \"enter\" keydown', () =\u003E {\n let saveHandler = jest.fn()\n\n const { queryByPlaceholderText } = render(\u003CAddComment onSave={saveHandler} \u002F\u003E)\n\n userEvent.type(queryByPlaceholderText('请输入新留言…'), commentText)\n fireEvent.keyDown(queryByPlaceholderText('请输入新留言…'), {\n key: 'Enter',\n code: 13,\n })\n\n expect(saveHandler).toBeCalledWith(commentText)\n expect(queryByPlaceholderText('请输入新留言…').value).toBe('')\n})\n","id":"mod_NhRRhz1qqMk8RsP2Rx8uxD","is_binary":false,"title":"AddComment.test.js","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"HJs-bQU0iNU","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"B1c-X80jE8"},{"code":"import { List } from 'antd'\nimport React from 'react'\nimport { isEmpty } from 'lodash'\nimport { Empty } from 'antd'\n\nexport function CommentList({ comments, sortType }) {\n if (isEmpty(comments)) {\n return \u003CEmpty description=\"留言为空\" \u002F\u003E\n }\n\n return (\n \u003CList\n dataSource={sortType === 'oldest' ? comments : [...comments].reverse()}\n renderItem={item =\u003E (\n \u003Cdiv data-testid=\"comment-content\" key={item}\u003E\n {item}\n \u003C\u002Fdiv\u003E\n )}\n \u002F\u003E\n )\n}\n","id":"mod_RytijL7LQZXvNZTPhCHMXy","is_binary":false,"title":"CommentList.js","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"Hy6Z-m8Ai4I","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"B1c-X80jE8"},{"code":"import { render } from '@testing-library\u002Freact'\nimport React from 'react'\nimport { CommentList } from '.\u002FCommentList'\n\nit('should show empty content when no comments', () =\u003E {\n const { queryByText } = render(\u003CCommentList comments={[]} \u002F\u003E)\n\n expect(queryByText('留言为空')).toBeTruthy()\n})\n\nit('should show comments content when have comments', () =\u003E {\n const { queryByText, queryAllByTestId } = render(\n \u003CCommentList comments={['comment1', 'comment2']} \u002F\u003E\n )\n\n expect(queryByText('留言为空')).toBeFalsy()\n expect(queryAllByTestId('comment-content').map(i =\u003E i.textContent))\n .toMatchInlineSnapshot(`\n Array [\n \"comment2\",\n \"comment1\",\n ]\n `)\n})\n","id":"mod_Rgfu5c9wf3farN9ZHpUChB","is_binary":false,"title":"CommentList.test.js","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"H1RZbmIRoV8","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"B1c-X80jE8"},{"code":"import { Row, Select } from 'antd'\nimport React from 'react'\n\nexport function CommentTitle({ comments, onSort }) {\n return (\n \u003CRow type=\"flex\"\u003E\n \u003Ch2 data-testid=\"comment-title\"\u003E\n {!comments || comments.length === 0\n ? '留言板'\n : `${comments.length} 留言`}\n \u003C\u002Fh2\u003E\n \u003CSelect\n style={{ width: 100 }}\n data-testid=\"sort-comment\"\n defaultValue={['latest']}\n onChange={value =\u003E onSort(value)}\n \u003E\n \u003CSelect.Option value=\"latest\"\u003E默认\u003C\u002FSelect.Option\u003E\n \u003CSelect.Option value=\"oldest\"\u003E从旧到新\u003C\u002FSelect.Option\u003E\n \u003C\u002FSelect\u003E\n \u003C\u002FRow\u003E\n )\n}\n","id":"mod_DRkBF3JNzKPABFLsN5jie4","is_binary":false,"title":"CommentTitle.js","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"SJJfWQ8Ai4I","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"B1c-X80jE8"},{"code":"import { action } from '@storybook\u002Faddon-actions'\nimport React from 'react'\nimport { CommentTitle } from '.\u002FCommentTitle'\n\nexport default {\n title: 'CommentTitle',\n}\n\nexport const add = () =\u003E \u003CCommentTitle onSort={action('sortHandler')} \u002F\u003E\n","id":"mod_GHbY16NvKgv4swiw24JQ2c","is_binary":false,"title":"CommentTitle.stories.js","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"HJxf-mICj4I","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"B1c-X80jE8"},{"code":"import userEvent from '@testing-library\u002Fuser-event'\nimport React from 'react'\nimport { CommentTitle } from '.\u002FCommentTitle'\nimport { render } from '@testing-library\u002Freact'\nconst comments = ['comment1', 'comment2']\n\nit('should show init title when no comments', () =\u003E {\n const { queryByText } = render(\u003CCommentTitle comments={[]} \u002F\u003E)\n expect(queryByText('留言板')).toBeTruthy()\n})\n\nit('should show title with count when have comments', () =\u003E {\n const { queryByText, queryByTestId } = render(\n \u003CCommentTitle comments={comments} \u002F\u003E\n )\n expect(queryByText('留言板')).toBeFalsy()\n expect(queryByTestId('comment-title')).toHaveTextContent('2 留言')\n})\n\nit('should call sortBy when select sort selections', () =\u003E {\n let sortHandler = jest.fn()\n const { queryByTestId, queryByText } = render(\n \u003CCommentTitle comments={comments} onSort={sortHandler} \u002F\u003E\n )\n\n userEvent.click(queryByTestId('sort-comment'))\n userEvent.click(queryByText('从旧到新'))\n\n expect(sortHandler).toBeCalledWith('oldest')\n})\n","id":"mod_BA3cwVysXQBKqqqtZ4owvJ","is_binary":false,"title":"CommentTitle.test.js","sha":null,"inserted_at":"2020-03-03T13:05:29","updated_at":"2020-03-03T13:05:29","upload_id":null,"shortid":"BkZzbXUCiVU","source_id":"src_2fCjBigpryr81F3hG3pm5X","directory_shortid":"B1c-X80jE8"}],"entry":"src\u002Findex.js","inserted_at":"2020-02-17T09:57:28","collection":false,"external_resources":[],"authorization":"read","pr_number":null,"template":"create-react-app","is_frozen":false,"user_liked":false,"description":null,"tags":[],"team":null,"preview_secret":null,"ai_consent":false,"alias":"tdd-commentbox-yc5mj","sdk":false,"restricted":false,"free_plan_editing_restricted":false,"fork_count":8,"restrictions":{"free_plan_editing_restricted":false,"live_sessions_restricted":true},"version":2,"always_on":false,"forked_template":null,"id":"yc5mj","original_git":null,"v2":false,"npm_registries":[],"settings":{"ai_consent":null,"use_pint":false},"permissions":{"prevent_sandbox_export":false,"prevent_sandbox_leaving":false},"source_id":"src_2fCjBigpryr81F3hG3pm5X","like_count":0,"owned":false,"picks":[],"forked_from_sandbox":null,"feature_flags":{"comments":false,"container_lsp":false}};