【发布时间】:2021-08-13 10:09:25
【问题描述】:
我想在将动作传递给子项时测试我的组件动作。简而言之,像 twitter 或 facebook 这样的每个来源都有自己的一组操作。我想检查它是否被调用或不使用间谍。
这是我的动作组件
const targetMetric = 'account dropdown'
const availableActions = {
addQuery: {
facebook: '^facebook://page/',
twitter: true
},
exclude: {
blog: [
'^blog://user/eventregistry/',
'^eventregistry://user/'
],
news: [
'^news://user/eventregistry/',
'^eventregistry://user/'
],
twitter: true,
youtube: true
},
reportAsNews: {
youtube: true,
mastodon: true,
twitter: true
}
}
const requiredHandlers = {
exclude: [
'onExcludeProfile'
],
reportAsNews: [
'onReportAsNews'
]
}
class Actions extends React.PureComponent {
get actions() {
const { account, handlers } = this.props
const actions = {};
Object.keys(availableActions).forEach(key =>
actions[ key ] = false
)
Object.keys(actions).forEach(key => {
const value = (
!!account.uri
&&
availableActions[ key ][ account.type ]
)
if (!value) {
return
}
if (typeof value === 'boolean') {
actions[ key ] = value
return
}
if (typeof value === 'string') {
const re = new RegExp(value, 'i')
actions[ key ] = re.test(account.uri)
return
}
if (
typeof value === 'object'
&&
Array.isArray(value)
) {
actions[ key ] = value.some(v => {
const re = new RegExp(v, 'i')
return re.test(account.uri)
})
}
})
Object.keys(actions).forEach(key => {
if (!actions[ key ] || !requiredHandlers[ key ]) {
return
}
actions[ key ] = requiredHandlers[ key ].some(i => handlers[ i ])
})
if (actions.addQuery) {
actions.addQuery = Object
.keys(this.addQueryActions)
.some(key => this.addQueryActions[ key ])
}
return actions
}
get addQueryActions() {
const { availableLanguages = [], userIsAdmin } = this.context
const { caseItem, handlers } = this.props
const actions = {
addQueryToFilter: !caseItem.isPaused && !!handlers.onAddQuery,
addQueryToAccountList: userIsAdmin && !!handlers.onAddToAccountList
}
actions.addQueryToSearch = actions.addQueryToFilter && !!availableLanguages.length
return actions
}
get actor() {
return pick(
this.props.account,
[ 'uri', 'name', 'link' ]
)
}
onExclude = () => {
const { account, handlers, isCaseLocked } = this.props
if (isCaseLocked) {
return
}
handlers.onExcludeProfile(account)
}
onReportAsNews = () => this.props.handlers.onReportAsNews(this.actor)
onAddToAccountList = () => {
const { account, from, handlers } = this.props
handlers.onAddToAccountList(account, from)
}
onAddToQuery = type => ({ language } = {}) => {
const { account, caseItem, handlers } = this.props
const { id } = caseItem
const metrics = {
index: getId(),
language,
type
}
handlers.onAddQuery({
...metrics,
expression: this.expressionFromAccount(account),
hideSearch: true,
id,
})
return metrics
}
expressionFromAccount = account => ({
and: [
{ account }
]
})
trackExcludeEvent = () => {
const { account } = this.props
this.trackEvent(
events.excludeAccounts,
{
accountsAdded: 1,
source: account.type
}
)
}
trackCreateNewQueryEvent = ({ index, language, type }) => {
const eventNameMap = {
filters: events.createNewFilter,
queries: events.createNewSearch,
}
const metrics = {
queryId: index,
target: targetMetric
}
if (type === 'queries') {
metrics[ 'language' ] = language.toLowerCase()
}
this.trackEvent(
eventNameMap[ type ],
metrics
)
}
trackReportAsNewsEvent = () => (
this.trackEvent(
events.reportAsNews,
{ source: this.props.account.type }
)
)
trackEvent = (eventName, props = {}) => {
const { from, message } = this.props
eventTracker.track(
eventName,
{
...props,
from,
messageUri: message.uri
}
)
}
getLangMenuActions = ({ handlers, isCaseLocked }, { availableLanguages }) => {
if (
isCaseLocked
||
!availableLanguages
||
!handlers.onAddQuery
) {
return []
}
const onClick = compose(
this.trackCreateNewQueryEvent,
this.onAddToQuery('queries')
)
return availableLanguages.map(({ label, value: language }) => ({
handler: onClick.bind(this, { language }),
id: `add-account-to-search-lang-${language}`,
label
}))
}
getActions = () => {
const { isCaseLocked } = this.props
const { userIsAdmin } = this.context
const actions = []
if (this.actions.addQuery) {
const addQueryAction = {
id: 'add-account-to',
isInactive: isCaseLocked && !userIsAdmin,
label: i18n.t('SOURCES.DROPDOWN_ADD_TO'),
children: []
}
if (this.addQueryActions.addQueryToSearch) {
addQueryAction.children.push({
id: 'add-account-to-search',
isInactive: isCaseLocked,
label: i18n.t('SOURCES.DROPDOWN_NEW_SEARCH'),
children: this.getLangMenuActions(this.props, this.context)
})
}
if (this.addQueryActions.addQueryToFilter) {
addQueryAction.children.push({
handler: compose(
this.trackCreateNewQueryEvent,
this.onAddToQuery('filters')
),
id: 'add-account-to-filter',
isInactive: isCaseLocked,
label: i18n.t('SOURCES.DROPDOWN_NEW_FILTER')
})
}
if (this.addQueryActions.addQueryToAccountList) {
addQueryAction.children.push({
handler: this.onAddToAccountList,
id: 'add-account-to-account-list',
label: i18n.t('SOURCES.DROPDOWN_ACCOUNT_LIST')
})
}
actions.push(addQueryAction)
}
if (this.actions.reportAsNews) {
actions.push({
handler: compose(
this.onReportAsNews,
this.trackReportAsNewsEvent
),
id: 'report-as-news',
label: i18n.t('SOURCES.DROPDOWN_REPORT_AS_NEWS')
})
}
if (this.actions.exclude) {
actions.push({
handler: compose(
this.onExclude,
this.trackExcludeEvent
),
id: 'exclude-account',
isInactive: isCaseLocked,
label: i18n.t('SOURCES.DROPDOWN_EXCLUDE')
})
}
console.log(actions)
return actions
}
render() {
return this.props.children({
actions: this.getActions()
})
}
}
这是我的测试文件
import expect from 'expect'
const injectActions = require('inject-loader!./actions')
const Actions = injectActions({
'cm/common/event-tracker': {
eventTracker: {
track: () => {},
clear: () => {}
},
events: {
createNewFilter: '...',
createNewSearch: '...',
excludeAccounts: '...',
reportAsNews: '...',
}
},
}).default
const handlers = {
onAddQuery: () => { },
onAddToAccountList: () => { },
onExcludeProfile: () => { },
onReportAsNews: () => { }
}
const testProps = {
twitter: {
account: {
name: 'Twitter account',
uri: 'twitter://status/12345',
type: 'twitter'
},
handlers,
},
facebookPage: {
account: {
name: 'Facebook page account',
uri: 'facebook://page/12345',
type: 'facebook'
},
handlers
}
}
describe('Actions component', () => {
let node
beforeEach(() => {
node = document.createElement('div')
})
afterEach(() => {
ReactDOM.unmountComponentAtNode(node)
})
it('returns empty actions array by default', () => {
const spyFn = expect.createSpy().andReturn(null)
ReactDOM.render(
<Actions>{spyFn}</Actions>,
node
)
expect(spyFn).toHaveBeenCalledWith({ actions: [] })
})
describe('Twitter', () => {
it('returns "Exclude" action', () => {
const { account, handlers } = testProps.twitter
const spyFn = expect.createSpy()
ReactDOM.render(
<Actions
account={account}
handlers={{
onExcludeProfile: handlers.onExcludeProfile
}}
isCaseLocked={false}
>
{spyFn}
</Actions>,
node
)
expect(spyFn).toHaveBeenCalledWith({ actions: [
{
handler: () => {},
id: 'exclude-account',
isInactive: false,
label: 'Exclude',
}
] })
})
})
第一个单元格工作正常,但第二个是错误的。其实我也不需要那里的所有对象。我只想确定它在那里包含id: 'exclude-account'。
请大家帮忙。
【问题讨论】:
标签: reactjs unit-testing jestjs