<commit_before>import React from 'react'
import PropTypes from 'prop-types'
import { Link } from 'react-router'
import classNames from 'classnames'
import {
  BadgeFeaturedIcon,
  CheckCircleIcon,
} from '../assets/Icons'
import { RoundedRectLink } from '../buttons/Buttons'
import { before, css, hover, media, select } from '../../styles/jss'
import * as s from '../../styles/jso'

const categoryCheckStyle = css(
  s.absolute,
  s.inlineBlock,
  {
    marginLeft: -44,
    marginTop: -6,
    width: 40,
    transform: 'scale(1.6)',
  },
  select('& .svg-stroke-bevel', s.strokeGreen),
  select('& circle', s.strokeGreen),

  media(s.maxBreak2,
    {
      marginLeft: -28,
      marginTop: -2,
      width: 28,
      transform: 'none',
    },
  ),
  media('(max-width: 26.25em)', // 420 / 16 = 26.25em
    {
      marginLeft: -25,
      marginTop: -2,
      width: 26,
      transform: 'scale(0.86)',
    },
  ),
)

export function CategorySubscribedIcon({ isSubscribed }) {
  if (!isSubscribed) { return null }
  return (
    <span className={`category-check ${categoryCheckStyle}`}>
      <CheckCircleIcon />

  )
}
CategorySubscribedIcon.propTypes = {
  isSubscribed: PropTypes.bool.isRequired,
}

const categorySubscribeButtonStyle = css(
  s.bgcGreen,
  s.colorWhite,
  {
    padding: '5px 15px 5px 6px',
    borderRadius: 100,
    transition: `background-color 0.2s ${s.ease}`,
  },
  hover({ backgroundColor: '#16a905' }),
  select('&.subscribed',
    s.bgcA,
    hover(s.bgcBlack),
  ),
  select('& .text',
    s.fontSize12,
    s.inlineBlock,
    s.pl10,
    { paddingTop: 4 },
  ),
  select('& .CheckCircleIcon', s.inlineBlock, { marginTop: -2 }),
)

export function CategorySubscribeButton({ isSubscribed, subscribe, unsubscribe }) {
  return (
    <button
      className={`${categorySubscribeButtonStyle} subscribe-button${isSubscribed ? ' subscribed' : ''}`}
      onClick={!isSubscribed ? subscribe : unsubscribe}
    >
      <CheckCircleIcon />

        {!isSubscribed ? 'Subscribe' : 'Subscribed'}

    </button>
  )
}
CategorySubscribeButton.propTypes = {
  isSubscribed: PropTypes.bool.isRequired,
  subscribe: PropTypes.func.isRequired,
  unsubscribe: PropTypes.func.isRequired,
}

const categorySubNavStyle = css(
  s.relative,
  s.fullWidth,
  s.pt20,
  s.pb0,
  s.center,
  s.resetList,

  media(s.minBreak2,
    s.pt40,
    s.pb20,
  ),

  select('& li',
    s.inlineBlock,
    {
      marginRight: 15,
      marginLeft: 15,
    },
    select('& a',
      s.fontSize16,
      s.colorA,
      {
        border: 'none',
      },

      media(s.minBreak2,
        s.fontSize18,
      ),
    ),

    select('&.selected',
      select('& a',
        s.colorBlack,
        s.borderBottom,
      ),
    ),
  ),

  // style mobile-specific version
  media(s.maxBreak2,
    s.pr10,
    s.pl10,

    select('& li',
      s.relative,
      s.inlineBlock,
      s.m0,
      s.center,
      s.borderBottom,
      {
        width: '50%',
        borderColor: '#aaa',
      },
      select('& a',
        { borderWidth: '0' },
      ),
      select('&.selected',
        { borderColor: '#000' },
        select('& a',
          { borderWidth: '0' },
        ),
      ),
    ),
    select('&.global li',
      { width: '33.3333333%' },
    ),
  ),
)

export function CategorySubNav({ stream, kind }) {
  if (stream === 'global') {
    return (
      <ul className={`category-sub-nav global ${categorySubNavStyle}`}>

          <Link to="/discover">
            Featured
          </Link>

          <Link to="/discover/trending">
            Trending
          </Link>

          <Link to="/discover/recent">
            Recent
          </Link>

    )
  }
  return (
    <ul className={`category-sub-nav ${categorySubNavStyle}`}>

        <Link to={`/discover/${stream}`}>
          Featured
        </Link>

        <Link to={`/discover/${stream}/trending`}>
          Trending
        </Link>

  )
}
CategorySubNav.propTypes = {
  stream: PropTypes.string.isRequired,
  kind: PropTypes.string.isRequired,
}

const categoryCardLinkStyle = css(
  s.absolute,
  s.flex,
  s.itemsCenter,
  s.fullWidth,
  s.fullHeight,
  s.bgcBlack,
  { backgroundSize: 'cover' },
  before(
    s.absolute,
    s.flood,
    s.zIndex2,
    s.transitionBgColor,
    { content: '""', backgroundColor: 'rgba(0, 0, 0, 0.7)' },
  ),
  hover(before({ backgroundColor: 'rgba(0, 0, 0, 0.3)' })),

  media('(max-width: 26.25em)', // 420 / 16 = 26.25em
    s.block,
  ),
)

const CategoryCardLink = ({ children, imageUrl, to }) => (
  <Link
    className={categoryCardLinkStyle}
    to={to}
    style={imageUrl ? { backgroundImage: `url("${imageUrl}")` } : null}
  >
    {children}
  </Link>
)
CategoryCardLink.propTypes = {
  children: PropTypes.node.isRequired,
  imageUrl: PropTypes.string,
  to: PropTypes.string.isRequired,
}

CategoryCardLink.defaultProps = {
  imageUrl: null,
}

const categoryCardTitleStyle = css(
  s.relative,
  s.block,
  s.mAuto,
  s.colorWhite,
  s.fontSize32,
  s.center,
  s.zIndex3,
  { width: 'calc(100% - 100px)' },

  media(s.maxBreak2,
    s.fontSize18,
  ),
  media('(max-width: 26.25em)', // 420 / 16 = 26.25em
    s.fontSize16,
    { width: 'calc(100% - 50px)' },
  ),

  select('& .category-check',
    { marginTop: -6 },
    media(s.maxBreak2,
      { marginTop: -2 },
    ),
  ),
)

const CategoryCardTitle = ({ name, isSubscribed }) => (
  <span className={`${categoryCardTitleStyle} title-holder`}>
    <CategorySubscribedIcon isSubscribed={isSubscribed} />
    {name}

)
CategoryCardTitle.propTypes = {
  name: PropTypes.string.isRequired,
  isSubscribed: PropTypes.bool,
}
CategoryCardTitle.defaultProps = {
  isSubscribed: false,
}

// Card for /discover/all
const categoryCardStyle = css(
  s.relative,
  s.block,
  {
    margin: '0 20px 40px 20px',
    width: 'calc(25% - 40px)',
    paddingBottom: 'calc(25% - 40px)',
  },

  media(s.maxBreak4,
    {
      margin: '0 10px 20px 10px',
      width: 'calc(33.3333333% - 20px)',
      paddingBottom: 'calc(33.3333333% - 20px)',
    },
  ),
  media(s.maxBreak3,
    {
      width: 'calc(50% - 20px)',
      paddingBottom: 'calc(50% - 20px)',
    },
  ),
  media(s.maxBreak2,
    {
      margin: '0 5px 10px 5px',
      width: 'calc(50% - 10px)',
      paddingBottom: 'calc(50% - 10px)',
    },
  ),

  media(s.minBreak5,
    {
      width: 'calc(20% - 40px)',
      paddingBottom: 'calc(20% - 40px)',
    },
  ),
  media(s.minBreak6,
    {
      width: 'calc(16.666666667% - 40px)',
      paddingBottom: 'calc(16.666666667% - 40px)',
    },
  ),
  media(s.minBreak7,
    {
      width: 'calc(14.28571429% - 40px)',
      paddingBottom: 'calc(14.28571429% - 40px)',
    },
  ),

  // featured badge
  select('& .featured-badge',
    s.absolute,
    s.zIndex2,
    { top: 10, right: -5 },
  ),

  // subscribe button positioning
  select('& .button-holder',
    s.absolute,
    s.flex,
    s.justifyCenter,
    s.fullWidth,
    s.zIndex3,
    { bottom: 40 },

    media(s.maxBreak2,
      { bottom: 20 },
    ),
  ),
  select('& .title-holder',
    media('(max-width: 26.25em)', // 420 / 16 = 26.25em
      // s.absolute,
      { top: 20 },
    ),
  ),
)

export const CategoryCard = ({
  name,
  imageUrl,
  to,
  isSubscribed,
  isPromo,
  subscribe,
  unsubscribe,
}) => (

    <CategoryCardLink imageUrl={imageUrl} to={to}>
      {isPromo &&

          <BadgeFeaturedIcon />

      }
      <CategoryCardTitle
        className="title-holder"
        name={name}
        isSubscribed={isSubscribed}
      />

        <CategorySubscribeButton
          subscribe={subscribe}
          unsubscribe={unsubscribe}
          isSubscribed={isSubscribed}
        />

    </CategoryCardLink>

)
CategoryCard.propTypes = {
  name: PropTypes.string.isRequired,
  imageUrl: PropTypes.string,
  to: PropTypes.string.isRequired,
  isSubscribed: PropTypes.bool.isRequired,
  isPromo: PropTypes.bool.isRequired,
  subscribe: PropTypes.func.isRequired,
  unsubscribe: PropTypes.func.isRequired,
}

CategoryCard.defaultProps = {
  imageUrl: null,
}

// footer for /discover/all style
const categoryAllFooterStyle = css(
  s.fixed,
  s.flex,
  s.fullWidth,
  s.itemsCenter,
  s.justifyCenter,
  s.bgcF2,
  s.zIndex4,
  {
    bottom: 0,
    left: 0,
    height: 50,
  },
  media(s.minBreak2,
    { height: 80 },
  ),
)

export const CategoryAllFooter = () => (

      <RoundedRectLink
        to="/discover/subscribed"
        className=""
      >
        View Subscriptions
      </RoundedRectLink>

)

<commit_msg>categories - all - featured - mobile size<commit_after>import React from 'react'
import PropTypes from 'prop-types'
import { Link } from 'react-router'
import classNames from 'classnames'
import {
  BadgeFeaturedIcon,
  CheckCircleIcon,
} from '../assets/Icons'
import { RoundedRectLink } from '../buttons/Buttons'
import { before, css, hover, media, select } from '../../styles/jss'
import * as s from '../../styles/jso'

const categoryCheckStyle = css(
  s.absolute,
  s.inlineBlock,
  {
    marginLeft: -44,
    marginTop: -6,
    width: 40,
    transform: 'scale(1.6)',
  },
  select('& .svg-stroke-bevel', s.strokeGreen),
  select('& circle', s.strokeGreen),

  media(s.maxBreak2,
    {
      marginLeft: -28,
      marginTop: -2,
      width: 28,
      transform: 'none',
    },
  ),
  media('(max-width: 26.25em)', // 420 / 16 = 26.25em
    {
      marginLeft: -25,
      marginTop: -2,
      width: 26,
      transform: 'scale(0.86)',
    },
  ),
)

export function CategorySubscribedIcon({ isSubscribed }) {
  if (!isSubscribed) { return null }
  return (
    <span className={`category-check ${categoryCheckStyle}`}>
      <CheckCircleIcon />

  )
}
CategorySubscribedIcon.propTypes = {
  isSubscribed: PropTypes.bool.isRequired,
}

const categorySubscribeButtonStyle = css(
  s.bgcGreen,
  s.colorWhite,
  {
    padding: '5px 15px 5px 6px',
    borderRadius: 100,
    transition: `background-color 0.2s ${s.ease}`,
  },
  hover({ backgroundColor: '#16a905' }),
  select('&.subscribed',
    s.bgcA,
    hover(s.bgcBlack),
  ),
  select('& .text',
    s.fontSize12,
    s.inlineBlock,
    s.pl10,
    { paddingTop: 4 },
  ),
  select('& .CheckCircleIcon', s.inlineBlock, { marginTop: -2 }),
)

export function CategorySubscribeButton({ isSubscribed, subscribe, unsubscribe }) {
  return (
    <button
      className={`${categorySubscribeButtonStyle} subscribe-button${isSubscribed ? ' subscribed' : ''}`}
      onClick={!isSubscribed ? subscribe : unsubscribe}
    >
      <CheckCircleIcon />

        {!isSubscribed ? 'Subscribe' : 'Subscribed'}

    </button>
  )
}
CategorySubscribeButton.propTypes = {
  isSubscribed: PropTypes.bool.isRequired,
  subscribe: PropTypes.func.isRequired,
  unsubscribe: PropTypes.func.isRequired,
}

const categorySubNavStyle = css(
  s.relative,
  s.fullWidth,
  s.pt20,
  s.pb0,
  s.center,
  s.resetList,

  media(s.minBreak2,
    s.pt40,
    s.pb20,
  ),

  select('& li',
    s.inlineBlock,
    {
      marginRight: 15,
      marginLeft: 15,
    },
    select('& a',
      s.fontSize16,
      s.colorA,
      {
        border: 'none',
      },

      media(s.minBreak2,
        s.fontSize18,
      ),
    ),

    select('&.selected',
      select('& a',
        s.colorBlack,
        s.borderBottom,
      ),
    ),
  ),

  // style mobile-specific version
  media(s.maxBreak2,
    s.pr10,
    s.pl10,

    select('& li',
      s.relative,
      s.inlineBlock,
      s.m0,
      s.center,
      s.borderBottom,
      {
        width: '50%',
        borderColor: '#aaa',
      },
      select('& a',
        { borderWidth: '0' },
      ),
      select('&.selected',
        { borderColor: '#000' },
        select('& a',
          { borderWidth: '0' },
        ),
      ),
    ),
    select('&.global li',
      { width: '33.3333333%' },
    ),
  ),
)

export function CategorySubNav({ stream, kind }) {
  if (stream === 'global') {
    return (
      <ul className={`category-sub-nav global ${categorySubNavStyle}`}>

          <Link to="/discover">
            Featured
          </Link>

          <Link to="/discover/trending">
            Trending
          </Link>

          <Link to="/discover/recent">
            Recent
          </Link>

    )
  }
  return (
    <ul className={`category-sub-nav ${categorySubNavStyle}`}>

        <Link to={`/discover/${stream}`}>
          Featured
        </Link>

        <Link to={`/discover/${stream}/trending`}>
          Trending
        </Link>

  )
}
CategorySubNav.propTypes = {
  stream: PropTypes.string.isRequired,
  kind: PropTypes.string.isRequired,
}

const categoryCardLinkStyle = css(
  s.absolute,
  s.flex,
  s.itemsCenter,
  s.fullWidth,
  s.fullHeight,
  s.bgcBlack,
  { backgroundSize: 'cover' },
  before(
    s.absolute,
    s.flood,
    s.zIndex2,
    s.transitionBgColor,
    { content: '""', backgroundColor: 'rgba(0, 0, 0, 0.7)' },
  ),
  hover(before({ backgroundColor: 'rgba(0, 0, 0, 0.3)' })),

  media('(max-width: 26.25em)', // 420 / 16 = 26.25em
    s.block,
  ),
)

const CategoryCardLink = ({ children, imageUrl, to }) => (
  <Link
    className={categoryCardLinkStyle}
    to={to}
    style={imageUrl ? { backgroundImage: `url("${imageUrl}")` } : null}
  >
    {children}
  </Link>
)
CategoryCardLink.propTypes = {
  children: PropTypes.node.isRequired,
  imageUrl: PropTypes.string,
  to: PropTypes.string.isRequired,
}

CategoryCardLink.defaultProps = {
  imageUrl: null,
}

const categoryCardTitleStyle = css(
  s.relative,
  s.block,
  s.mAuto,
  s.colorWhite,
  s.fontSize32,
  s.center,
  s.zIndex3,
  { width: 'calc(100% - 100px)' },

  media(s.maxBreak2,
    s.fontSize18,
  ),
  media('(max-width: 26.25em)', // 420 / 16 = 26.25em
    s.fontSize16,
    { width: 'calc(100% - 50px)' },
  ),

  select('& .category-check',
    { marginTop: -6 },
    media(s.maxBreak2,
      { marginTop: -2 },
    ),
  ),
)

const CategoryCardTitle = ({ name, isSubscribed }) => (
  <span className={`${categoryCardTitleStyle} title-holder`}>
    <CategorySubscribedIcon isSubscribed={isSubscribed} />
    {name}

)
CategoryCardTitle.propTypes = {
  name: PropTypes.string.isRequired,
  isSubscribed: PropTypes.bool,
}
CategoryCardTitle.defaultProps = {
  isSubscribed: false,
}

// Card for /discover/all
const categoryCardStyle = css(
  s.relative,
  s.block,
  {
    margin: '0 20px 40px 20px',
    width: 'calc(25% - 40px)',
    paddingBottom: 'calc(25% - 40px)',
  },

  media(s.maxBreak4,
    {
      margin: '0 10px 20px 10px',
      width: 'calc(33.3333333% - 20px)',
      paddingBottom: 'calc(33.3333333% - 20px)',
    },
  ),
  media(s.maxBreak3,
    {
      width: 'calc(50% - 20px)',
      paddingBottom: 'calc(50% - 20px)',
    },
  ),
  media(s.maxBreak2,
    {
      margin: '0 5px 10px 5px',
      width: 'calc(50% - 10px)',
      paddingBottom: 'calc(50% - 10px)',
    },
  ),

  media(s.minBreak5,
    {
      width: 'calc(20% - 40px)',
      paddingBottom: 'calc(20% - 40px)',
    },
  ),
  media(s.minBreak6,
    {
      width: 'calc(16.666666667% - 40px)',
      paddingBottom: 'calc(16.666666667% - 40px)',
    },
  ),
  media(s.minBreak7,
    {
      width: 'calc(14.28571429% - 40px)',
      paddingBottom: 'calc(14.28571429% - 40px)',
    },
  ),

  // featured badge
  select('& .featured-badge',
    s.absolute,
    s.zIndex2,
    { top: 10, right: -5 },
    media(s.maxBreak2,
      { top: 3, right: -7 },
      select('& .BadgeFeaturedIcon',
        { transform: 'scale(0.64)' },
      ),
    ),
  ),

  // subscribe button positioning
  select('& .button-holder',
    s.absolute,
    s.flex,
    s.justifyCenter,
    s.fullWidth,
    s.zIndex3,
    { bottom: 40 },

    media(s.maxBreak2,
      { bottom: 20 },
    ),
  ),
  select('& .title-holder',
    media('(max-width: 26.25em)', // 420 / 16 = 26.25em
      { top: 20 },
    ),
  ),
)

export const CategoryCard = ({
  name,
  imageUrl,
  to,
  isSubscribed,
  isPromo,
  subscribe,
  unsubscribe,
}) => (

    <CategoryCardLink imageUrl={imageUrl} to={to}>
      {isPromo &&

          <BadgeFeaturedIcon />

      }
      <CategoryCardTitle
        className="title-holder"
        name={name}
        isSubscribed={isSubscribed}
      />

        <CategorySubscribeButton
          subscribe={subscribe}
          unsubscribe={unsubscribe}
          isSubscribed={isSubscribed}
        />

    </CategoryCardLink>

)
CategoryCard.propTypes = {
  name: PropTypes.string.isRequired,
  imageUrl: PropTypes.string,
  to: PropTypes.string.isRequired,
  isSubscribed: PropTypes.bool.isRequired,
  isPromo: PropTypes.bool.isRequired,
  subscribe: PropTypes.func.isRequired,
  unsubscribe: PropTypes.func.isRequired,
}

CategoryCard.defaultProps = {
  imageUrl: null,
}

// footer for /discover/all style
const categoryAllFooterStyle = css(
  s.fixed,
  s.flex,
  s.fullWidth,
  s.itemsCenter,
  s.justifyCenter,
  s.bgcF2,
  s.zIndex4,
  {
    bottom: 0,
    left: 0,
    height: 50,
  },
  media(s.minBreak2,
    { height: 80 },
  ),
)

export const CategoryAllFooter = () => (

      <RoundedRectLink
        to="/discover/subscribed"
        className=""
      >
        View Subscriptions
      </RoundedRectLink>

)

<|endoftext|>


<commit_before>import React from 'react'
import Icon from 'react-fa'

import {shallow, mount} from 'enzyme'
import {TestRoot} from 'gComponents/rootTestComponent'
import DropDown from 'gComponents/utility/drop-down/index'

import {SpaceToolbar} from './index'

import CanvasViewForm from '../canvasViewForm'

describe('<SpaceToolbar>', () => {
  it ('Always shows the view form', () => {
    const toolbar = shallow(<SpaceToolbar />)
    expect(toolbar.containsMatchingElement(<CanvasViewForm/>)).to.equal(true)
  })

  it ('Disables the undo/redo buttons when they are unavailable', () => {
    const toolbar = shallow(
      <SpaceToolbar
        canUndo={false}
        canRedo={false}
      />
    )
    expect(toolbar.find('.header-action')).to.have.length(6)
    expect(toolbar.find('.header-action.disabled')).to.have.length(2)
  })

  it ('Renders the file menu only if you are logged in', () => {
    let toolbar = shallow(<SpaceToolbar isLoggedIn={false} />)
    expect(toolbar.containsMatchingElement(
      <DropDown openLink={File} />
    )).to.equal(false)
  })
})
<commit_msg>Fixed broken test<commit_after>import React from 'react'
import Icon from 'react-fa'

import {shallow, mount} from 'enzyme'
import {TestRoot} from 'gComponents/rootTestComponent'
import DropDown from 'gComponents/utility/drop-down/index'

import {SpaceToolbar} from './index'

import CanvasViewForm from '../canvasViewForm'

describe('<SpaceToolbar>', () => {
  it ('Always shows the view form', () => {
    const toolbar = shallow(<SpaceToolbar />)
    expect(toolbar.containsMatchingElement(<CanvasViewForm/>)).to.equal(true)
  })

  it ('Disables the undo/redo buttons when they are unavailable', () => {
    const toolbar = shallow(
      <SpaceToolbar
        canUndo={false}
        canRedo={false}
      />
    )
    expect(toolbar.find('.header-action')).to.have.length(7)
    expect(toolbar.find('.header-action.disabled')).to.have.length(2)
  })

  it ('Renders the file menu only if you are logged in', () => {
    let toolbar = shallow(<SpaceToolbar isLoggedIn={false} />)
    expect(toolbar.containsMatchingElement(
      <DropDown openLink={File} />
    )).to.equal(false)
  })
})
<|endoftext|>


<commit_before>import React from 'react';

// components
import {
  withStyles,
  Grid,
  Checkbox,
  Radio,
  FormControlLabel,
} from '@material-ui/core'

import { Link } from 'react-router-dom'

// custom components
import InfoArea from 'components/MaterialDashboardPro/InfoArea'
import ProfileForm from 'containers/Profile/ProfileForm'

// icons
import DoneIcon from '@material-ui/icons/Done'
import Check from '@material-ui/icons/Check'
import FiberManualRecord from "@material-ui/icons/FiberManualRecord"

// style
import customSelectStyle from 'styles/material-dashboard-pro-react/customSelectStyle.jsx';
import customCheckboxRadioSwitch from 'styles/material-dashboard-pro-react/customCheckboxRadioSwitch.jsx';

const style = {
  ...customSelectStyle,
  ...customCheckboxRadioSwitch
};

class Step1 extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      selectedValue: 'individual'
    };
  }

  handleChange = event => {
    this.setState({ selectedValue: event.target.value });

    if (this.props.onSignupTypeChange) {
      this.props.onSignupTypeChange(event.target.value);
    }
  }

  handleToggle = value => {
    const { checked } = this.state;
    const currentIndex = checked.indexOf(value);
    const newChecked = [...checked];

    if (currentIndex === -1) {
      newChecked.push(value);
    } else {
      newChecked.splice(currentIndex, 1);
    }

    this.setState({
      checked: newChecked
    });
  }

  toggleAcceptTerms = () => {
    this.props.setAcceptTermsAndConditions(!this.props.acceptedTerms)
  }

  setProfileFormRef = profileForm => this.profileForm = profileForm

  submit = values => {
    console.log(values)
    console.log(this.props)
    return this.props.onProfileSubmitted(values)
  }

  render() {
    const { classes, wallet } = this.props;

    if (wallet && wallet.did) {
      return (
        <Grid container justify='center'>
          <Grid item xs={4}>
            <InfoArea
              icon={DoneIcon}
              iconColor='success'
              title='All done'
              description='Your wallet is ready to go'
            />
          </Grid>
        </Grid>
      )
    } else {
      return (
        <form action='/myreputation' className={classes.form} onSubmit={this.testSubmit}>
          <Grid container justify='center' spacing={16}>
            <Grid item xs={12} sm={12} md={5}>
              <FormControlLabel
                classes={{ label: classes.label }}
                label='Create A Consumer Account'
                control={
                  <Radio
                    id='userAccount'
                    checked={this.state.selectedValue === 'individual'}
                    onChange={this.handleChange}
                    value='individual'
                    name='radio button demo'
                    aria-label='A'
                    icon={<FiberManualRecord className={classes.radioUnchecked} />}
                    checkedIcon={<FiberManualRecord className={classes.radioChecked} />}
                    classes={{ checked: classes.radio }}
                  />
                }
              />
            </Grid>

            <Grid item xs={12} sm={12} md={5}>
              <FormControlLabel
                classes={{ label: classes.label }}
                label='Create A Business Account'
                control={
                  <Radio
                    checked={this.state.selectedValue === 'business'}
                    onChange={this.handleChange}
                    value='business'
                    name='radio button demo'
                    aria-label='B'
                    icon={<FiberManualRecord className={classes.radioUnchecked} />}
                    checkedIcon={<FiberManualRecord className={classes.radioChecked} />}
                    classes={{ checked: classes.radio }}
                  />
                }
              />
            </Grid>

            <ProfileForm
              ref={this.setProfileFormRef}
              userType={this.state.selectedValue}
              onSubmit={this.submit}
            />

            <Grid item xs={12} sm={12} md={10}>
              <FormControlLabel
                classes={{ root: classes.checkboxLabelControl, label: classes.checkboxLabel }}
                label={I agree to the <Link to='/terms'>terms and conditions</Link>.}
                control={
                  <Checkbox
                    tabIndex={-1}
                    checked={this.props.acceptedTerms}
                    onClick={this.toggleAcceptTerms}
                    checkedIcon={<Check className={classes.checkedIcon} />}
                    icon={<Check className={classes.uncheckedIcon} />}
                    classes={{ checked: classes.checked }}
                  />
                }
              />
            </Grid>
          </Grid>
        </form>
      )
    }
  }
}

export default withStyles(style)(Step1)
<commit_msg>remove dead code<commit_after>import React from 'react';

// components
import {
  withStyles,
  Grid,
  Checkbox,
  Radio,
  FormControlLabel,
} from '@material-ui/core'

import { Link } from 'react-router-dom'

// custom components
import InfoArea from 'components/MaterialDashboardPro/InfoArea'
import ProfileForm from 'containers/Profile/ProfileForm'

// icons
import DoneIcon from '@material-ui/icons/Done'
import Check from '@material-ui/icons/Check'
import FiberManualRecord from "@material-ui/icons/FiberManualRecord"

// style
import customSelectStyle from 'styles/material-dashboard-pro-react/customSelectStyle.jsx';
import customCheckboxRadioSwitch from 'styles/material-dashboard-pro-react/customCheckboxRadioSwitch.jsx';

const style = {
  ...customSelectStyle,
  ...customCheckboxRadioSwitch
};

class Step1 extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      selectedValue: 'individual'
    };
  }

  handleChange = event => {
    this.setState({ selectedValue: event.target.value });

    if (this.props.onSignupTypeChange) {
      this.props.onSignupTypeChange(event.target.value);
    }
  }

  handleToggle = value => {
    const { checked } = this.state;
    const currentIndex = checked.indexOf(value);
    const newChecked = [...checked];

    if (currentIndex === -1) {
      newChecked.push(value);
    } else {
      newChecked.splice(currentIndex, 1);
    }

    this.setState({
      checked: newChecked
    });
  }

  toggleAcceptTerms = () => {
    this.props.setAcceptTermsAndConditions(!this.props.acceptedTerms)
  }

  submit = values => {
    console.log(values)
    console.log(this.props)
    return this.props.onProfileSubmitted(values)
  }

  render() {
    const { classes, wallet } = this.props;

    if (wallet && wallet.did) {
      return (
        <Grid container justify='center'>
          <Grid item xs={4}>
            <InfoArea
              icon={DoneIcon}
              iconColor='success'
              title='All done'
              description='Your wallet is ready to go'
            />
          </Grid>
        </Grid>
      )
    } else {
      return (
        <form action='/myreputation' className={classes.form} onSubmit={this.testSubmit}>
          <Grid container justify='center' spacing={16}>
            <Grid item xs={12} sm={12} md={5}>
              <FormControlLabel
                classes={{ label: classes.label }}
                label='Create A Consumer Account'
                control={
                  <Radio
                    id='userAccount'
                    checked={this.state.selectedValue === 'individual'}
                    onChange={this.handleChange}
                    value='individual'
                    name='radio button demo'
                    aria-label='A'
                    icon={<FiberManualRecord className={classes.radioUnchecked} />}
                    checkedIcon={<FiberManualRecord className={classes.radioChecked} />}
                    classes={{ checked: classes.radio }}
                  />
                }
              />
            </Grid>

            <Grid item xs={12} sm={12} md={5}>
              <FormControlLabel
                classes={{ label: classes.label }}
                label='Create A Business Account'
                control={
                  <Radio
                    checked={this.state.selectedValue === 'business'}
                    onChange={this.handleChange}
                    value='business'
                    name='radio button demo'
                    aria-label='B'
                    icon={<FiberManualRecord className={classes.radioUnchecked} />}
                    checkedIcon={<FiberManualRecord className={classes.radioChecked} />}
                    classes={{ checked: classes.radio }}
                  />
                }
              />
            </Grid>

            <ProfileForm
              userType={this.state.selectedValue}
              onSubmit={this.submit}
            />

            <Grid item xs={12} sm={12} md={10}>
              <FormControlLabel
                classes={{ root: classes.checkboxLabelControl, label: classes.checkboxLabel }}
                label={I agree to the <Link to='/terms'>terms and conditions</Link>.}
                control={
                  <Checkbox
                    tabIndex={-1}
                    checked={this.props.acceptedTerms}
                    onClick={this.toggleAcceptTerms}
                    checkedIcon={<Check className={classes.checkedIcon} />}
                    icon={<Check className={classes.uncheckedIcon} />}
                    classes={{ checked: classes.checked }}
                  />
                }
              />
            </Grid>
          </Grid>
        </form>
      )
    }
  }
}

export default withStyles(style)(Step1)
<|endoftext|>


<commit_before>// parent class
import {RestClient} from "../rest-client.js";

export default class OpenCGAParentClass {

    constructor(config) {
        this._config = config;
        // this.token = null;
        this.restClient = new RestClient();
    }

    _get(category1, ids1, category2, ids2, action, params, options) {
        // we store the options from the parameter or from the default values in config

        // first attempt of solving https://github.com/opencb/jsorolla/issues/153
        // cannot use `params` in key as we want to cancel queries from the same origin (ajax function) but different params.
        const k = this.generateKey(params);

        const host = this._config.host;
        const version = this._config.version;
        // const rpc = this._config.mode;
        const _options = options || {};

        const method = _options?.method || "GET";

        const _params = params || {};

        // Check that sessionId is being given
        if (!_params.sid) {
            const sid = this._getSessionId();
            if (typeof sid !== "undefined") {
                _options.sid = sid;
                _options.token = sid;
            }
        }

        // If category == users and userId is not given, we try to set it
        if (category1 === "users" && (ids1 === undefined || ids1 === null || ids1 === "")) {
            ids1 = this._getUserId();
        }
        let url = this._createRestUrl(host, version, category1, ids1, category2, ids2, action);
        // if (method === "GET") {
        url = this._addQueryParams(url, _params);
        if (method === "POST") {
            _options.data = _params.body;
            if (action === "upload") {
                _options["post-method"] = "form";
            }
        }
        // console.log(`OpenCGA client calling to ${url}`);
        // if the URL query fails we try with next host
        return this.restClient.call(url, _options, k);

    }

    _post(category1, ids1, category2, ids2, action, body, params = {}, options = {}) {
        // Clear and Revert actions do not need a body, but needs a params
        if (category2 === "interpretation" && (action === "clear" || action === "revert")) {
            // eslint-disable-next-line no-param-reassign
            params = body;
            // eslint-disable-next-line no-param-reassign
            body = {};
        }
        const host = this._config.host;
        const version = this._config.version;
        // const rpc = this._config.mode;
        const k = this.generateKey(params);
        const _options = {...options, method: "POST"};
        if (this._config.token) {
            _options.sid = this._config.token;
            _options.token = this._config.token;
        }
        const _params = {...params, body: body}; // body as param?
        let url = this._createRestUrl(host, version, category1, ids1, category2, ids2, action);
        url = this._addQueryParams(url, _params);
        _options.data = _params.body;
        if (action === "upload") {
            _options["post-method"] = "form";
        }
        return this.restClient.call(url, _options, k);
    }

    // recheck
    _delete(category1, ids1, category2, ids2, action, body, params = {}) {
        const host = this._config.host;
        const version = this._config.version;
        const _options = {method: "DELETE"};
        const k = this.generateKey(params);
        if (this._config.token) {
            // _options.sid = this._config.token;
            _options.token = this._config.token;
        }
        // const _params = {...params, body: body};
        const _params = {...params, ...body};
        let url = this._createRestUrl(host, version, category1, ids1, category2, ids2, action);
        url = this._addQueryParams(url, _params);
        // _options.data = _params.body;
        // _options.body = _params.body;

        return this.restClient.call(url, _options, k);
    }

    _createRestUrl(host, version, category1, ids1, category2, ids2, action) {
        let url = host + `/webservices/rest/${version}/${category1}/`;
        // By default we assume https protocol instead of http
        if (!url.startsWith("https://") && !url.startsWith("http://")) {
            url = `https://${host}/webservices/rest/${version}/${category1}/`;
        }

        // Some web services do not need IDs
        if (typeof ids1 !== "undefined" && ids1 !== null) {
            url += `${ids1}/`;
        }

        // Some web services do not need a second category
        if (typeof category2 !== "undefined" && category2 !== null) {
            url += `${category2}/`;
        }

        // Some web services do not need the second category of ids
        if (typeof ids2 !== "undefined" && ids2 !== null && ids2 !== "") {
            url += `${ids2}/`;
        }

        url += action;

        return url;
    }

    _addQueryParams(url, params) {
        // We add the query params formatted in URL
        const queryParamsUrl = this._createQueryParam(params);
        let _url = url;
        if (typeof queryParamsUrl !== "undefined" && queryParamsUrl !== null && queryParamsUrl !== "") {
            _url += `?${queryParamsUrl}`;
        }
        return _url;
    }

    _createQueryParam(params) {
        // Do not remove the sort! we need to sort the array to ensure that the key of the cache will be correct
        const keyArray = Object.keys(params);
        const keyValueArray = [];
        for (const i in keyArray) {
            // Whatever it is inside body will be sent hidden via POST
            if (keyArray[i] !== "body") {
                keyValueArray.push(`${keyArray[i]}=${encodeURIComponent(params[keyArray[i]])}`);
            }
        }
        return keyValueArray.join("&");
    }

    _getUserId() {
        return this._config.userId;
    }

    _getSessionId() {
        return this._config.token;
    }

    setToken(token) {
        // this.token = token;
        this._config.token = token;
    }

    getToken() {
        return this._config.token;
    }

    generateKey(params) {
        // if concurrent=true the request bypass the request queue in RestClient
        return params?.concurrent !== true ? `${new Error().stack.split("\n    at ").slice(0, 5).join("|")}${params?.study}` : false;
    }

}
<commit_msg>core: disable generateKey in opencga client #TASK-670<commit_after>// parent class
import {RestClient} from "../rest-client.js";

export default class OpenCGAParentClass {

    constructor(config) {
        this._config = config;
        // this.token = null;
        this.restClient = new RestClient();
    }

    _get(category1, ids1, category2, ids2, action, params, options) {
        // we store the options from the parameter or from the default values in config

        // first attempt of solving https://github.com/opencb/jsorolla/issues/153
        // cannot use `params` in key as we want to cancel queries from the same origin (ajax function) but different params.
        const k = this.generateKey(params);

        const host = this._config.host;
        const version = this._config.version;
        // const rpc = this._config.mode;
        const _options = options || {};

        const method = _options?.method || "GET";

        const _params = params || {};

        // Check that sessionId is being given
        if (!_params.sid) {
            const sid = this._getSessionId();
            if (typeof sid !== "undefined") {
                _options.sid = sid;
                _options.token = sid;
            }
        }

        // If category == users and userId is not given, we try to set it
        if (category1 === "users" && (ids1 === undefined || ids1 === null || ids1 === "")) {
            ids1 = this._getUserId();
        }
        let url = this._createRestUrl(host, version, category1, ids1, category2, ids2, action);
        // if (method === "GET") {
        url = this._addQueryParams(url, _params);
        if (method === "POST") {
            _options.data = _params.body;
            if (action === "upload") {
                _options["post-method"] = "form";
            }
        }
        // console.log(`OpenCGA client calling to ${url}`);
        // if the URL query fails we try with next host
        return this.restClient.call(url, _options, k);

    }

    _post(category1, ids1, category2, ids2, action, body, params = {}, options = {}) {
        // Clear and Revert actions do not need a body, but needs a params
        if (category2 === "interpretation" && (action === "clear" || action === "revert")) {
            // eslint-disable-next-line no-param-reassign
            params = body;
            // eslint-disable-next-line no-param-reassign
            body = {};
        }
        const host = this._config.host;
        const version = this._config.version;
        // const rpc = this._config.mode;
        const k = this.generateKey(params);
        const _options = {...options, method: "POST"};
        if (this._config.token) {
            _options.sid = this._config.token;
            _options.token = this._config.token;
        }
        const _params = {...params, body: body}; // body as param?
        let url = this._createRestUrl(host, version, category1, ids1, category2, ids2, action);
        url = this._addQueryParams(url, _params);
        _options.data = _params.body;
        if (action === "upload") {
            _options["post-method"] = "form";
        }
        return this.restClient.call(url, _options, k);
    }

    // recheck
    _delete(category1, ids1, category2, ids2, action, body, params = {}) {
        const host = this._config.host;
        const version = this._config.version;
        const _options = {method: "DELETE"};
        const k = this.generateKey(params);
        if (this._config.token) {
            // _options.sid = this._config.token;
            _options.token = this._config.token;
        }
        // const _params = {...params, body: body};
        const _params = {...params, ...body};
        let url = this._createRestUrl(host, version, category1, ids1, category2, ids2, action);
        url = this._addQueryParams(url, _params);
        // _options.data = _params.body;
        // _options.body = _params.body;

        return this.restClient.call(url, _options, k);
    }

    _createRestUrl(host, version, category1, ids1, category2, ids2, action) {
        let url = host + `/webservices/rest/${version}/${category1}/`;
        // By default we assume https protocol instead of http
        if (!url.startsWith("https://") && !url.startsWith("http://")) {
            url = `https://${host}/webservices/rest/${version}/${category1}/`;
        }

        // Some web services do not need IDs
        if (typeof ids1 !== "undefined" && ids1 !== null) {
            url += `${ids1}/`;
        }

        // Some web services do not need a second category
        if (typeof category2 !== "undefined" && category2 !== null) {
            url += `${category2}/`;
        }

        // Some web services do not need the second category of ids
        if (typeof ids2 !== "undefined" && ids2 !== null && ids2 !== "") {
            url += `${ids2}/`;
        }

        url += action;

        return url;
    }

    _addQueryParams(url, params) {
        // We add the query params formatted in URL
        const queryParamsUrl = this._createQueryParam(params);
        let _url = url;
        if (typeof queryParamsUrl !== "undefined" && queryParamsUrl !== null && queryParamsUrl !== "") {
            _url += `?${queryParamsUrl}`;
        }
        return _url;
    }

    _createQueryParam(params) {
        // Do not remove the sort! we need to sort the array to ensure that the key of the cache will be correct
        const keyArray = Object.keys(params);
        const keyValueArray = [];
        for (const i in keyArray) {
            // Whatever it is inside body will be sent hidden via POST
            if (keyArray[i] !== "body") {
                keyValueArray.push(`${keyArray[i]}=${encodeURIComponent(params[keyArray[i]])}`);
            }
        }
        return keyValueArray.join("&");
    }

    _getUserId() {
        return this._config.userId;
    }

    _getSessionId() {
        return this._config.token;
    }

    setToken(token) {
        // this.token = token;
        this._config.token = token;
    }

    getToken() {
        return this._config.token;
    }

    generateKey() {
        // Josemi 2022-04-22 NOTE: disabled key generation. See task https://app.clickup.com/t/36631768/TASK-670
        // return params?.concurrent !== true ? `${new Error().stack.split("\n    at ").slice(0, 5).join("|")}${params?.study}` : false;
        return "";
    }

}
<|endoftext|>


<commit_before>const { expect } = require('chai');
const app = require('../../../../src/app');
const testObjects = require('../../helpers/testObjects')(app);
const { generateRequestParamsFromUser } = require('../../helpers/services/login')(app);

const courseScopeListService = app.service('/users/:scopeId/courses');

const oneHour = 600000;
const twoDays = 172800000;

describe('courses scopelist service', () => {
	it('is properly registered', () => {
		expect(courseScopeListService).to.not.equal(undefined);
	});

	it('fetches only active courses by default', async () => {
		const user = await testObjects.createTestUser();
		const activeCourse = await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const archivedCourse = await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() - twoDays,
		});
		const response = await courseScopeListService.find({ route: { scopeId: user._id }, query: {} });
		expect(response).to.not.equal(undefined);
		expect(response.total).to.equal(1);
		expect(response.data).to.not.equal(undefined);
		const courseIds = response.data.map((course) => course._id.toString());
		expect(courseIds.includes(activeCourse._id.toString())).to.equal(true);
		expect(courseIds.includes(archivedCourse._id.toString())).to.equal(false);
	});

	it('may explicitly fetch only active courses', async () => {
		const user = await testObjects.createTestUser();
		const activeCourse = await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const archivedCourse = await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() - twoDays,
		});
		const response = await courseScopeListService.find({
			route: { scopeId: user._id },
			query: { filter: 'active' },
		});
		expect(response).to.not.equal(undefined);
		expect(response.total).to.equal(1);
		expect(response.data).to.not.equal(undefined);
		const courseIds = response.data.map((course) => course._id.toString());
		expect(courseIds.includes(activeCourse._id.toString())).to.equal(true);
		expect(courseIds.includes(archivedCourse._id.toString())).to.equal(false);
	});

	it('may fetch only archived courses', async () => {
		const user = await testObjects.createTestUser();
		const activeCourse = await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const archivedCourse = await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() - twoDays,
		});
		const response = await courseScopeListService.find({
			route: { scopeId: user._id },
			query: { filter: 'archived' },
		});
		expect(response).to.not.equal(undefined);
		expect(response.total).to.equal(1);
		expect(response.data).to.not.equal(undefined);
		const courseIds = response.data.map((course) => course._id.toString());
		expect(courseIds.includes(activeCourse._id.toString())).to.equal(false);
		expect(courseIds.includes(archivedCourse._id.toString())).to.equal(true);
	});

	it('may fetch all courses', async () => {
		const user = await testObjects.createTestUser();
		const activeCourse = await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const archivedCourse = await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() - twoDays,
		});
		const response = await courseScopeListService.find({
			route: { scopeId: user._id },
			query: { filter: 'all' },
		});
		expect(response).to.not.equal(undefined);
		expect(response.total).to.equal(2);
		expect(response.data).to.not.equal(undefined);
		const courseIds = response.data.map((course) => course._id.toString());
		expect(courseIds.includes(activeCourse._id.toString())).to.equal(true);
		expect(courseIds.includes(archivedCourse._id.toString())).to.equal(true);
	});

	it('fetches all courses by default', async () => {
		const user = await testObjects.createTestUser();
		const courseAsStudent = await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const courseAsTeacher = await testObjects.createTestCourse({
			teacherIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const courseAsSubstitutionTeacher = await testObjects.createTestCourse({
			substitutionIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const response = await courseScopeListService.find({
			route: { scopeId: user._id },
			query: {},
		});
		expect(response).to.not.equal(undefined);
		expect(response.total).to.equal(3);
		expect(response.data).to.not.equal(undefined);
		const courseIds = response.data.map((course) => course._id.toString());
		expect(courseIds.includes(courseAsStudent._id.toString())).to.equal(true);
		expect(courseIds.includes(courseAsTeacher._id.toString())).to.equal(true);
		expect(courseIds.includes(courseAsSubstitutionTeacher._id.toString())).to.equal(true);
	});

	it('may fetch only courses as student/teacher', async () => {
		const user = await testObjects.createTestUser();
		const courseAsStudent = await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const courseAsTeacher = await testObjects.createTestCourse({
			teacherIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const courseAsSubstitutionTeacher = await testObjects.createTestCourse({
			substitutionIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const response = await courseScopeListService.find({
			route: { scopeId: user._id },
			query: { substitution: 'false' },
		});
		expect(response).to.not.equal(undefined);
		expect(response.total).to.equal(2);
		expect(response.data).to.not.equal(undefined);
		const courseIds = response.data.map((course) => course._id.toString());
		expect(courseIds.includes(courseAsStudent._id.toString())).to.equal(true);
		expect(courseIds.includes(courseAsTeacher._id.toString())).to.equal(true);
		expect(courseIds.includes(courseAsSubstitutionTeacher._id.toString())).to.equal(false);
	});

	it('may fetch only courses as substitution teacher', async () => {
		const user = await testObjects.createTestUser();
		const courseAsStudent = await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const courseAsTeacher = await testObjects.createTestCourse({
			teacherIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const courseAsSubstitutionTeacher = await testObjects.createTestCourse({
			substitutionIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const response = await courseScopeListService.find({
			route: { scopeId: user._id },
			query: { substitution: 'true' },
		});
		expect(response).to.not.equal(undefined);
		expect(response.total).to.equal(1);
		expect(response.data).to.not.equal(undefined);
		const courseIds = response.data.map((course) => course._id.toString());
		expect(courseIds.includes(courseAsStudent._id.toString())).to.equal(false);
		expect(courseIds.includes(courseAsTeacher._id.toString())).to.equal(false);
		expect(courseIds.includes(courseAsSubstitutionTeacher._id.toString())).to.equal(true);
	});

	it('may fetch as both substitution teacher and student/teacher', async () => {
		const user = await testObjects.createTestUser();
		const courseAsStudent = await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const courseAsTeacher = await testObjects.createTestCourse({
			teacherIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const courseAsSubstitutionTeacher = await testObjects.createTestCourse({
			substitutionIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const response = await courseScopeListService.find({
			route: { scopeId: user._id },
			query: { substitution: 'all' },
		});
		expect(response).to.not.equal(undefined);
		expect(response.total).to.equal(3);
		expect(response.data).to.not.equal(undefined);
		const courseIds = response.data.map((course) => course._id.toString());
		expect(courseIds.includes(courseAsStudent._id.toString())).to.equal(true);
		expect(courseIds.includes(courseAsTeacher._id.toString())).to.equal(true);
		expect(courseIds.includes(courseAsSubstitutionTeacher._id.toString())).to.equal(true);
	});

	it('passes on pagination', async () => {
		const user = await testObjects.createTestUser();
		const response = await courseScopeListService.find({
			route: { scopeId: user._id },
			query: { $limit: 23, $skip: 18 },
		});
		expect(response).to.not.equal(undefined);
		expect(response.limit).to.equal(23);
		expect(response.skip).to.equal(18);
	});

	it('allows disabling pagination', async () => {
		const user = await testObjects.createTestUser();
		const response = await courseScopeListService.find({
			route: { scopeId: user._id },
			query: {},
			paginate: false,
		});
		expect(response).to.not.equal(undefined);
		expect(Array.isArray(response)).to.equal(true);
	});

	it('may return count of active courses', async () => {
		const user = await testObjects.createTestUser();
		await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() - twoDays,
		});
		await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() - twoDays,
		});
		const response = await courseScopeListService.find({
			route: { scopeId: user._id },
			query: { count: 'true' },
			paginate: false,
		});
		expect(response).to.deep.equal({
			total: 1,
		});
	});

	it('may return count of active courses', async () => {
		const user = await testObjects.createTestUser();
		await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() - twoDays,
		});
		await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() - twoDays,
		});
		const response = await courseScopeListService.find({
			route: { scopeId: user._id },
			query: { filter: 'archived', count: 'true' },
			paginate: false,
		});
		expect(response).to.deep.equal({
			total: 2,
		});
	});

	afterEach(testObjects.cleanup);
});

describe('courses scopelist service integration', () => {
	let server;

	before((done) => {
		server = app.listen(0, done);
	});

	after((done) => {
		server.close(done);
	});

	it('fails without authorization', async () => {
		try {
			const user = await testObjects.createTestUser();
			await courseScopeListService.find({
				route: { scopeId: user._id },
				query: {},
				provider: 'rest',
			});
			throw new Error('should have failed');
		} catch (err) {
			expect(err).to.not.equal(undefined);
			expect(err.name).to.equal('NotAuthenticated');
			expect(err.message).to.equal('No auth token');
		}
	});

	it('fails for different users', async () => {
		try {
			const user = await testObjects.createTestUser();
			const targetUser = await testObjects.createTestUser();
			const params = await generateRequestParamsFromUser(user);
			params.route = { scopeId: targetUser._id };
			params.query = {};
			await courseScopeListService.find(params);
			throw new Error('should have failed');
		} catch (err) {
			expect(err).to.not.equal(undefined);
			expect(err.name).to.equal('Forbidden');
			expect(err.message).to.equal('Requested and requesting userIds do not match.');
		}
	});

	it('succeeds for authenticated user', async () => {
		const user = await testObjects.createTestUser();
		const course = await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const params = await generateRequestParamsFromUser(user);
		params.route = { scopeId: user._id };
		params.query = {};
		const response = await courseScopeListService.find(params);
		expect(response).to.not.equal(undefined);
		expect(response.total).to.equal(1);
		expect(response.data).to.not.equal(undefined);
		expect(response.data[0]._id.toString()).to.equal(course._id.toString());
	});

	afterEach(testObjects.cleanup);
});
<commit_msg>Add longer timeouts<commit_after>const { expect } = require('chai');
const app = require('../../../../src/app');
const testObjects = require('../../helpers/testObjects')(app);
const { generateRequestParamsFromUser } = require('../../helpers/services/login')(app);

const courseScopeListService = app.service('/users/:scopeId/courses');

const oneHour = 600000;
const twoDays = 172800000;

describe('courses scopelist service', () => {
	it('is properly registered', () => {
		expect(courseScopeListService).to.not.equal(undefined);
	});

	it('fetches only active courses by default', async () => {
		const user = await testObjects.createTestUser();
		const activeCourse = await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const archivedCourse = await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() - twoDays,
		});
		const response = await courseScopeListService.find({ route: { scopeId: user._id }, query: {} });
		expect(response).to.not.equal(undefined);
		expect(response.total).to.equal(1);
		expect(response.data).to.not.equal(undefined);
		const courseIds = response.data.map((course) => course._id.toString());
		expect(courseIds.includes(activeCourse._id.toString())).to.equal(true);
		expect(courseIds.includes(archivedCourse._id.toString())).to.equal(false);
	});

	it('may explicitly fetch only active courses', async () => {
		const user = await testObjects.createTestUser();
		const activeCourse = await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const archivedCourse = await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() - twoDays,
		});
		const response = await courseScopeListService.find({
			route: { scopeId: user._id },
			query: { filter: 'active' },
		});
		expect(response).to.not.equal(undefined);
		expect(response.total).to.equal(1);
		expect(response.data).to.not.equal(undefined);
		const courseIds = response.data.map((course) => course._id.toString());
		expect(courseIds.includes(activeCourse._id.toString())).to.equal(true);
		expect(courseIds.includes(archivedCourse._id.toString())).to.equal(false);
	});

	it('may fetch only archived courses', async () => {
		const user = await testObjects.createTestUser();
		const activeCourse = await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const archivedCourse = await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() - twoDays,
		});
		const response = await courseScopeListService.find({
			route: { scopeId: user._id },
			query: { filter: 'archived' },
		});
		expect(response).to.not.equal(undefined);
		expect(response.total).to.equal(1);
		expect(response.data).to.not.equal(undefined);
		const courseIds = response.data.map((course) => course._id.toString());
		expect(courseIds.includes(activeCourse._id.toString())).to.equal(false);
		expect(courseIds.includes(archivedCourse._id.toString())).to.equal(true);
	});

	it('may fetch all courses', async () => {
		const user = await testObjects.createTestUser();
		const activeCourse = await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const archivedCourse = await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() - twoDays,
		});
		const response = await courseScopeListService.find({
			route: { scopeId: user._id },
			query: { filter: 'all' },
		});
		expect(response).to.not.equal(undefined);
		expect(response.total).to.equal(2);
		expect(response.data).to.not.equal(undefined);
		const courseIds = response.data.map((course) => course._id.toString());
		expect(courseIds.includes(activeCourse._id.toString())).to.equal(true);
		expect(courseIds.includes(archivedCourse._id.toString())).to.equal(true);
	});

	it('fetches all courses by default', async () => {
		const user = await testObjects.createTestUser();
		const courseAsStudent = await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const courseAsTeacher = await testObjects.createTestCourse({
			teacherIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const courseAsSubstitutionTeacher = await testObjects.createTestCourse({
			substitutionIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const response = await courseScopeListService.find({
			route: { scopeId: user._id },
			query: {},
		});
		expect(response).to.not.equal(undefined);
		expect(response.total).to.equal(3);
		expect(response.data).to.not.equal(undefined);
		const courseIds = response.data.map((course) => course._id.toString());
		expect(courseIds.includes(courseAsStudent._id.toString())).to.equal(true);
		expect(courseIds.includes(courseAsTeacher._id.toString())).to.equal(true);
		expect(courseIds.includes(courseAsSubstitutionTeacher._id.toString())).to.equal(true);
	});

	it('may fetch only courses as student/teacher', async () => {
		const user = await testObjects.createTestUser();
		const courseAsStudent = await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const courseAsTeacher = await testObjects.createTestCourse({
			teacherIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const courseAsSubstitutionTeacher = await testObjects.createTestCourse({
			substitutionIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const response = await courseScopeListService.find({
			route: { scopeId: user._id },
			query: { substitution: 'false' },
		});
		expect(response).to.not.equal(undefined);
		expect(response.total).to.equal(2);
		expect(response.data).to.not.equal(undefined);
		const courseIds = response.data.map((course) => course._id.toString());
		expect(courseIds.includes(courseAsStudent._id.toString())).to.equal(true);
		expect(courseIds.includes(courseAsTeacher._id.toString())).to.equal(true);
		expect(courseIds.includes(courseAsSubstitutionTeacher._id.toString())).to.equal(false);
	});

	it('may fetch only courses as substitution teacher', async () => {
		const user = await testObjects.createTestUser();
		const courseAsStudent = await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const courseAsTeacher = await testObjects.createTestCourse({
			teacherIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const courseAsSubstitutionTeacher = await testObjects.createTestCourse({
			substitutionIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const response = await courseScopeListService.find({
			route: { scopeId: user._id },
			query: { substitution: 'true' },
		});
		expect(response).to.not.equal(undefined);
		expect(response.total).to.equal(1);
		expect(response.data).to.not.equal(undefined);
		const courseIds = response.data.map((course) => course._id.toString());
		expect(courseIds.includes(courseAsStudent._id.toString())).to.equal(false);
		expect(courseIds.includes(courseAsTeacher._id.toString())).to.equal(false);
		expect(courseIds.includes(courseAsSubstitutionTeacher._id.toString())).to.equal(true);
	});

	it('may fetch as both substitution teacher and student/teacher', async () => {
		const user = await testObjects.createTestUser();
		const courseAsStudent = await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const courseAsTeacher = await testObjects.createTestCourse({
			teacherIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const courseAsSubstitutionTeacher = await testObjects.createTestCourse({
			substitutionIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const response = await courseScopeListService.find({
			route: { scopeId: user._id },
			query: { substitution: 'all' },
		});
		expect(response).to.not.equal(undefined);
		expect(response.total).to.equal(3);
		expect(response.data).to.not.equal(undefined);
		const courseIds = response.data.map((course) => course._id.toString());
		expect(courseIds.includes(courseAsStudent._id.toString())).to.equal(true);
		expect(courseIds.includes(courseAsTeacher._id.toString())).to.equal(true);
		expect(courseIds.includes(courseAsSubstitutionTeacher._id.toString())).to.equal(true);
	});

	it('passes on pagination', async () => {
		const user = await testObjects.createTestUser();
		const response = await courseScopeListService.find({
			route: { scopeId: user._id },
			query: { $limit: 23, $skip: 18 },
		});
		expect(response).to.not.equal(undefined);
		expect(response.limit).to.equal(23);
		expect(response.skip).to.equal(18);
	});

	it('allows disabling pagination', async () => {
		const user = await testObjects.createTestUser();
		const response = await courseScopeListService.find({
			route: { scopeId: user._id },
			query: {},
			paginate: false,
		});
		expect(response).to.not.equal(undefined);
		expect(Array.isArray(response)).to.equal(true);
	});

	it('may return count of active courses', async () => {
		const user = await testObjects.createTestUser();
		await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() - twoDays,
		});
		await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() - twoDays,
		});
		const response = await courseScopeListService.find({
			route: { scopeId: user._id },
			query: { count: 'true' },
			paginate: false,
		});
		expect(response).to.deep.equal({
			total: 1,
		});
	});

	it('may return count of active courses', async () => {
		const user = await testObjects.createTestUser();
		await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() - twoDays,
		});
		await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() - twoDays,
		});
		const response = await courseScopeListService.find({
			route: { scopeId: user._id },
			query: { filter: 'archived', count: 'true' },
			paginate: false,
		});
		expect(response).to.deep.equal({
			total: 2,
		});
	});

	afterEach(testObjects.cleanup);
});

describe('courses scopelist service integration', () => {
	let server;

	before((done) => {
		server = app.listen(0, done);
	});

	after((done) => {
		server.close(done);
	});

	it('fails without authorization', async () => {
		try {
			const user = await testObjects.createTestUser();
			await courseScopeListService.find({
				route: { scopeId: user._id },
				query: {},
				provider: 'rest',
			});
			throw new Error('should have failed');
		} catch (err) {
			expect(err).to.not.equal(undefined);
			expect(err.name).to.equal('NotAuthenticated');
			expect(err.message).to.equal('No auth token');
		}
	});

	it('fails for different users', async () => {
		try {
			const user = await testObjects.createTestUser();
			const targetUser = await testObjects.createTestUser();
			const params = await generateRequestParamsFromUser(user);
			params.route = { scopeId: targetUser._id };
			params.query = {};
			await courseScopeListService.find(params);
			throw new Error('should have failed');
		} catch (err) {
			expect(err).to.not.equal(undefined);
			expect(err.name).to.equal('Forbidden');
			expect(err.message).to.equal('Requested and requesting userIds do not match.');
		}
	}).timeout(4000);

	it('succeeds for authenticated user', async () => {
		const user = await testObjects.createTestUser();
		const course = await testObjects.createTestCourse({
			userIds: [user._id],
			untilDate: Date.now() + oneHour,
		});
		const params = await generateRequestParamsFromUser(user);
		params.route = { scopeId: user._id };
		params.query = {};
		const response = await courseScopeListService.find(params);
		expect(response).to.not.equal(undefined);
		expect(response.total).to.equal(1);
		expect(response.data).to.not.equal(undefined);
		expect(response.data[0]._id.toString()).to.equal(course._id.toString());
	}).timeout(4000);

	afterEach(testObjects.cleanup);
});
<|endoftext|>


<commit_before>var assert = require('chai').assert;
var _ = require('lodash');
var sinon = require('sinon');
var moment = require('moment');
var TestHelpers = require('../../support/TestHelpers');
var RunValidations = require('../../../client/js/app/utils/RunValidations');
var ExplorerValidations = require('../../../client/js/app/validations/ExplorerValidations');

describe('validations/ExplorerValidations', function() {

  describe('explorer query validations', function () {

    describe('refresh_rate validations', function() {
      it('has an error message', function () {
        var errorMessage = ExplorerValidations.refresh_rate.msg;
        assert.equal(errorMessage, 'Refresh rate must be between 4 and 24 hours.');
      });

      it('returns true when refresh rate is between 4 and 24 hours or 0', function() {
        assert.isTrue(ExplorerValidations.refresh_rate.validate({
          refresh_rate: 0
        }));
        assert.isTrue(ExplorerValidations.refresh_rate.validate({
          refresh_rate: 1440
        }));
        assert.isTrue(ExplorerValidations.refresh_rate.validate({
          refresh_rate: 2000
        }));
      });

      it('returns false when refresh_rate is out of range', function() {
        assert.isFalse(ExplorerValidations.refresh_rate.validate({
          refresh_rate: 1000
        }));
        assert.isFalse(ExplorerValidations.refresh_rate.validate({
          refresh_rate: 90000
        }));
      });
    });

    describe('query name', function () {
      it('has an error message', function () {
        var errorMessage = ExplorerValidations.query_name.msg;
        assert.equal(errorMessage, 'You must give your saved query a name.');
      });

      it('returns true even when the value is not valid when saving is false', function () {
        var explorer = TestHelpers.createExplorerModel();
        explorer.saving = false;
        explorer.query_name = '';
        RunValidations.run({ query_name: ExplorerValidations.query_name }, explorer);
        assert.strictEqual(explorer.errors.length, 0);
      });

      it('returns false when the value is not valid when saving is true', function () {
        var explorer = TestHelpers.createExplorerModel();
        explorer.saving = true;
        explorer.query_name = '';
        RunValidations.run({ query_name: ExplorerValidations.query_name }, explorer)
        assert.strictEqual(explorer.errors.length, 1);
      });

      it('returns true when name is present', function () {
        assert.isTrue(ExplorerValidations.query_name.validate({ saving: true, query_name: 'a satisfactory value' }));
      });

      it('returns false when name is an empty string', function () {
        assert.isFalse(ExplorerValidations.query_name.validate({ saving: true, query_name: '' }));
      });

      it('returns false when name is a null', function () {
        assert.isFalse(ExplorerValidations.query_name.validate({ saving: true, query_name: null }));
      });

      it('returns false when name is a undefined', function () {
        assert.isFalse(ExplorerValidations.query_name.validate({ saving: true, query_name: undefined }));
      });
    });

    describe('analysis_type', function () {
      it('has an error message', function () {
        var errorMessage = ExplorerValidations.analysis_type.msg;
        assert.equal(errorMessage, 'Choose an Analysis Type.');
      });

      it('returns true when analysis_type is present', function () {
        assert.isTrue(ExplorerValidations.analysis_type.validate({ query: { analysis_type: 'value' } }));
      });

      it('returns false when analysis_type is falsy', function () {
        assert.isFalse(ExplorerValidations.analysis_type.validate({ query: { analysis_type: '' } }));
      });
    });

    describe('event_collection', function () {
      it('shouldRun is false when the analysis_type is funnel', function () {
        assert.isFalse(ExplorerValidations.event_collection.shouldRun({ query: { analysis_type: 'funnel' } }));
      });
      it('shouldRun is true when the analysis_type is not', function () {
        assert.isTrue(ExplorerValidations.event_collection.shouldRun({ query: { analysis_type: 'count' } }));
      });
    });

    describe('filters', function () {
      describe('when query has invalid filters', function () {
        it('has an error message', function () {
          var errorMessage = ExplorerValidations.filters.msg;
          assert.equal(errorMessage, 'One of your filters is invalid.');
        });
      });

      describe('when query has valid filters', function () {
        it('returns true', function () {
          var filters = [
            {
              property_name: 'click',
              operator: 'eq',
              coercion_type: 'String',
              property_value: 'test string'
            }
          ];
          assert.isTrue(ExplorerValidations.filters.validate({ query: { filters: filters } }));
        });
      });

      describe('when the query has an invalid filter', function () {
        it('returns false', function () {
          var filters = [
            {
              property_name: 'click',
              operator: 'eq',
              coercion_type: 'Number',
              property_value: 'yoyoyo'
            }
          ];
          assert.isFalse(ExplorerValidations.filters.validate({ query: { filters: filters } }));
        });
      });

      describe('when query has no filters', function () {
        it('returns true', function () {
          assert.isTrue(ExplorerValidations.filters.validate({ query: { filters: [] } }));
        });
      });
    });
  });

  describe('email extraction field validations', function () {

    describe('email', function() {
      it("returns true when email has @ and .", function(){
        assert.isTrue(ExplorerValidations.email.validate({ query: { email: "keen@example.com" } }));
      });

      it('returns false when email is missing @ or .', function(){
        assert.isFalse(ExplorerValidations.email.validate({ query: { email: "keen@examplecom" } }));
        assert.isFalse(ExplorerValidations.email.validate({ query: { email: "keen!example.com" } }));
        assert.isFalse(ExplorerValidations.email.validate({ query: { email: "keen#example.com" } }));
        assert.isFalse(ExplorerValidations.email.validate({ query: { email: "keen$example.com" } }));
      });
    });

    describe('latest', function () {
      describe('evaluates strings correctly', function () {
        it('should return true for 10', function () {
          assert.isTrue(ExplorerValidations.latest.validate({ query: { latest: '10' } }));
        });

        it('should return false for 10.1', function () {
          assert.isFalse(ExplorerValidations.latest.validate({ query: { latest: '10.1' } }));
        });

        it('should return false for 10.00', function () {
          assert.isFalse(ExplorerValidations.latest.validate({ query: { latest: '10.00' } }));
        });
      });
    });
  });

  describe('Nested validations', function () {

    it('should set validation properties on filters', function () {
      var model = TestHelpers.createExplorerModel();
      model.query.event_collection = '';
      model.query.analysis_type = 'count';

      var filter1 = TestHelpers.createFilter();
      filter1.property_name = '';
      filter1.property_value = '';
      model.query.filters.push(filter1);

      var filter2 = TestHelpers.createFilter();
      filter2.property_name = 'name';
      filter2.operator = '';
      filter2.property_value = 'value';
      model.query.filters.push(filter2);

      RunValidations.run(ExplorerValidations, model);

      assert.isFalse(model.isValid);
      assert.strictEqual(model.errors.length, 2, 'Root model');

      assert.isFalse(model.query.filters[0].isValid);
      assert.strictEqual(model.query.filters[0].errors.length, 2);

      assert.isFalse(model.query.filters[1].isValid);
      assert.strictEqual(model.query.filters[1].errors.length, 1);
    });

    it('should set validation properties on steps and their filters', function () {
      var model = TestHelpers.createExplorerModel();
      model.query.event_collection = 'some collection';
      model.query.analysis_type = 'funnel';

      var step1 = TestHelpers.createStep();
      step1.event_collection = 'colletion';
      step1.actor_property = 'property';

      var filter1 = TestHelpers.createFilter();
      filter1.property_name = '';
      filter1.property_value = 'count';
      step1.filters.push(filter1)

      var filter2 = TestHelpers.createFilter();
      filter2.property_name = 'name';
      filter2.property_value = 'value';
      step1.filters.push(filter2);

      model.query.steps.push(step1);

      var step2 = TestHelpers.createStep();
      step2.event_collection = 'colletion';
      step2.actor_property = '';

      var filter3 = TestHelpers.createFilter();
      filter3.property_name = '';
      filter3.property_value = '';
      step2.filters.push(filter3)

      var filter4 = TestHelpers.createFilter();
      filter4.property_name = 'name';
      filter4.property_value = 'value';
      step2.filters.push(filter4);

      model.query.steps.push(step2);

      RunValidations.run(ExplorerValidations, model);

      var steps = model.query.steps;
      assert.isFalse(model.isValid, 'root model');
      assert.isFalse(steps[0].isValid, 'first step');
      assert.isFalse(steps[1].isValid, 'second setp');
      assert.isFalse(steps[0].filters[0].isValid, 'first filter of first step');
      assert.isTrue(steps[0].filters[1].isValid, 'second filter of first step');
      assert.isFalse(steps[1].filters[0].isValid, 'first filter of second step');
      assert.isTrue(steps[1].filters[1].isValid, 'second filter of secon step');

      assert.strictEqual(model.errors.length, 1);
      assert.strictEqual(steps[0].errors.length, 1);
      assert.strictEqual(steps[1].errors.length, 2);
      assert.strictEqual(steps[0].filters[0].errors.length, 1);
      assert.strictEqual(steps[0].filters[1].errors.length, 0);
      assert.strictEqual(steps[1].filters[0].errors.length, 2);
      assert.strictEqual(steps[1].filters[1].errors.length, 0);
    });

  });
});
<commit_msg>Update tests to allow empty filter property values<commit_after>var assert = require('chai').assert;
var _ = require('lodash');
var sinon = require('sinon');
var moment = require('moment');
var TestHelpers = require('../../support/TestHelpers');
var RunValidations = require('../../../client/js/app/utils/RunValidations');
var ExplorerValidations = require('../../../client/js/app/validations/ExplorerValidations');

describe('validations/ExplorerValidations', function() {

  describe('explorer query validations', function () {

    describe('refresh_rate validations', function() {
      it('has an error message', function () {
        var errorMessage = ExplorerValidations.refresh_rate.msg;
        assert.equal(errorMessage, 'Refresh rate must be between 4 and 24 hours.');
      });

      it('returns true when refresh rate is between 4 and 24 hours or 0', function() {
        assert.isTrue(ExplorerValidations.refresh_rate.validate({
          refresh_rate: 0
        }));
        assert.isTrue(ExplorerValidations.refresh_rate.validate({
          refresh_rate: 1440
        }));
        assert.isTrue(ExplorerValidations.refresh_rate.validate({
          refresh_rate: 2000
        }));
      });

      it('returns false when refresh_rate is out of range', function() {
        assert.isFalse(ExplorerValidations.refresh_rate.validate({
          refresh_rate: 1000
        }));
        assert.isFalse(ExplorerValidations.refresh_rate.validate({
          refresh_rate: 90000
        }));
      });
    });

    describe('query name', function () {
      it('has an error message', function () {
        var errorMessage = ExplorerValidations.query_name.msg;
        assert.equal(errorMessage, 'You must give your saved query a name.');
      });

      it('returns true even when the value is not valid when saving is false', function () {
        var explorer = TestHelpers.createExplorerModel();
        explorer.saving = false;
        explorer.query_name = '';
        RunValidations.run({ query_name: ExplorerValidations.query_name }, explorer);
        assert.strictEqual(explorer.errors.length, 0);
      });

      it('returns false when the value is not valid when saving is true', function () {
        var explorer = TestHelpers.createExplorerModel();
        explorer.saving = true;
        explorer.query_name = '';
        RunValidations.run({ query_name: ExplorerValidations.query_name }, explorer)
        assert.strictEqual(explorer.errors.length, 1);
      });

      it('returns true when name is present', function () {
        assert.isTrue(ExplorerValidations.query_name.validate({ saving: true, query_name: 'a satisfactory value' }));
      });

      it('returns false when name is an empty string', function () {
        assert.isFalse(ExplorerValidations.query_name.validate({ saving: true, query_name: '' }));
      });

      it('returns false when name is a null', function () {
        assert.isFalse(ExplorerValidations.query_name.validate({ saving: true, query_name: null }));
      });

      it('returns false when name is a undefined', function () {
        assert.isFalse(ExplorerValidations.query_name.validate({ saving: true, query_name: undefined }));
      });
    });

    describe('analysis_type', function () {
      it('has an error message', function () {
        var errorMessage = ExplorerValidations.analysis_type.msg;
        assert.equal(errorMessage, 'Choose an Analysis Type.');
      });

      it('returns true when analysis_type is present', function () {
        assert.isTrue(ExplorerValidations.analysis_type.validate({ query: { analysis_type: 'value' } }));
      });

      it('returns false when analysis_type is falsy', function () {
        assert.isFalse(ExplorerValidations.analysis_type.validate({ query: { analysis_type: '' } }));
      });
    });

    describe('event_collection', function () {
      it('shouldRun is false when the analysis_type is funnel', function () {
        assert.isFalse(ExplorerValidations.event_collection.shouldRun({ query: { analysis_type: 'funnel' } }));
      });
      it('shouldRun is true when the analysis_type is not', function () {
        assert.isTrue(ExplorerValidations.event_collection.shouldRun({ query: { analysis_type: 'count' } }));
      });
    });

    describe('filters', function () {
      describe('when query has invalid filters', function () {
        it('has an error message', function () {
          var errorMessage = ExplorerValidations.filters.msg;
          assert.equal(errorMessage, 'One of your filters is invalid.');
        });
      });

      describe('when query has valid filters', function () {
        it('returns true', function () {
          var filters = [
            {
              property_name: 'click',
              operator: 'eq',
              coercion_type: 'String',
              property_value: 'test string'
            }
          ];
          assert.isTrue(ExplorerValidations.filters.validate({ query: { filters: filters } }));
        });
      });

      describe('when the query has an invalid filter', function () {
        it('returns false', function () {
          var filters = [
            {
              property_name: 'click',
              operator: 'eq',
              coercion_type: 'Number',
              property_value: 'yoyoyo'
            }
          ];
          assert.isFalse(ExplorerValidations.filters.validate({ query: { filters: filters } }));
        });
      });

      describe('when query has no filters', function () {
        it('returns true', function () {
          assert.isTrue(ExplorerValidations.filters.validate({ query: { filters: [] } }));
        });
      });
    });
  });

  describe('email extraction field validations', function () {

    describe('email', function() {
      it("returns true when email has @ and .", function(){
        assert.isTrue(ExplorerValidations.email.validate({ query: { email: "keen@example.com" } }));
      });

      it('returns false when email is missing @ or .', function(){
        assert.isFalse(ExplorerValidations.email.validate({ query: { email: "keen@examplecom" } }));
        assert.isFalse(ExplorerValidations.email.validate({ query: { email: "keen!example.com" } }));
        assert.isFalse(ExplorerValidations.email.validate({ query: { email: "keen#example.com" } }));
        assert.isFalse(ExplorerValidations.email.validate({ query: { email: "keen$example.com" } }));
      });
    });

    describe('latest', function () {
      describe('evaluates strings correctly', function () {
        it('should return true for 10', function () {
          assert.isTrue(ExplorerValidations.latest.validate({ query: { latest: '10' } }));
        });

        it('should return false for 10.1', function () {
          assert.isFalse(ExplorerValidations.latest.validate({ query: { latest: '10.1' } }));
        });

        it('should return false for 10.00', function () {
          assert.isFalse(ExplorerValidations.latest.validate({ query: { latest: '10.00' } }));
        });
      });
    });
  });

  describe('Nested validations', function () {

    it('should set validation properties on filters', function () {
      var model = TestHelpers.createExplorerModel();
      model.query.event_collection = '';
      model.query.analysis_type = 'count';

      var filter1 = TestHelpers.createFilter();
      filter1.property_name = '';
      filter1.property_value = '';
      model.query.filters.push(filter1);

      var filter2 = TestHelpers.createFilter();
      filter2.property_name = 'name';
      filter2.operator = '';
      filter2.property_value = 'value';
      model.query.filters.push(filter2);

      RunValidations.run(ExplorerValidations, model);

      assert.isFalse(model.isValid);
      assert.strictEqual(model.errors.length, 2, 'Root model');

      assert.isFalse(model.query.filters[0].isValid);
      assert.strictEqual(model.query.filters[0].errors.length, 1);

      assert.isFalse(model.query.filters[1].isValid);
      assert.strictEqual(model.query.filters[1].errors.length, 1);
    });

    it('should set validation properties on steps and their filters', function () {
      var model = TestHelpers.createExplorerModel();
      model.query.event_collection = 'some collection';
      model.query.analysis_type = 'funnel';

      var step1 = TestHelpers.createStep();
      step1.event_collection = 'colletion';
      step1.actor_property = 'property';

      var filter1 = TestHelpers.createFilter();
      filter1.property_name = '';
      filter1.property_value = 'count';
      step1.filters.push(filter1)

      var filter2 = TestHelpers.createFilter();
      filter2.property_name = 'name';
      filter2.property_value = 'value';
      step1.filters.push(filter2);

      model.query.steps.push(step1);

      var step2 = TestHelpers.createStep();
      step2.event_collection = 'colletion';
      step2.actor_property = '';

      var filter3 = TestHelpers.createFilter();
      filter3.property_name = '';
      filter3.property_value = '';
      step2.filters.push(filter3)

      var filter4 = TestHelpers.createFilter();
      filter4.property_name = 'name';
      filter4.property_value = 'value';
      step2.filters.push(filter4);

      model.query.steps.push(step2);

      RunValidations.run(ExplorerValidations, model);

      var steps = model.query.steps;
      assert.isFalse(model.isValid, 'root model');
      assert.isFalse(steps[0].isValid, 'first step');
      assert.isFalse(steps[1].isValid, 'second setp');
      assert.isFalse(steps[0].filters[0].isValid, 'first filter of first step');
      assert.isTrue(steps[0].filters[1].isValid, 'second filter of first step');
      assert.isFalse(steps[1].filters[0].isValid, 'first filter of second step');
      assert.isTrue(steps[1].filters[1].isValid, 'second filter of secon step');

      assert.strictEqual(model.errors.length, 1);
      assert.strictEqual(steps[0].errors.length, 1);
      assert.strictEqual(steps[1].errors.length, 2);
      assert.strictEqual(steps[0].filters[0].errors.length, 1);
      assert.strictEqual(steps[0].filters[1].errors.length, 0);
      assert.strictEqual(steps[1].filters[0].errors.length, 1);
      assert.strictEqual(steps[1].filters[1].errors.length, 0);
    });

  });
});
<|endoftext|>


<commit_before>(function(module, fs, extend, moment, request, requestPromise, chai, liburl, Joi, helper, multipartParser, redirect)
{

/**  XAPI-00334, Communication 2.1.3 GET Statements
 * An LRS rejects a Statement of bad authorization (either authentication needed or failed credentials) with error code 401 Unauthorized
 */
 describe('An LRS rejects a Statement of bad authorization (either authentication needed or failed credentials) with error code 401 Unauthorized (Authentication 4.0 XAPI-00334)',function(){

    it("fails when given a random name pass pair", function(done)
    {
        var templates = [
        {
            statement: '{{statements.default}}'
        }];
        var data = helper.createFromTemplate(templates);
        data = data.statement;
        data.id = helper.generateUUID();
        var headers = helper.addAllHeaders(
        {});

        //warning: this ".\\" is super important. Node caches the modules, and the superrequest module has been modified to work correctly
        //with oauth already. We get a new verions by appending some other characters to defeat the cache.
        if(global.OAUTH)
            request = require('.\\super-request');
        else
            headers["Authorization"] = 'Basic ' + new Buffer('RobCIsNot:AUserOnThisLRS').toString('base64');
            request(helper.getEndpointAndAuth())
            .put(helper.getEndpointStatements() + '?statementId=' + data.id)
            .headers(headers)
            .json(data)
            .expect(401, done);
    });

    it('fails with a malformed header', function(done)
    {
        var templates = [
        {
            statement: '{{statements.default}}'
        }];
        var data = helper.createFromTemplate(templates);
        data = data.statement;
        data.id = helper.generateUUID();
        var headers = helper.addAllHeaders(
        {});

        //warning: this ".\\" is super important. Node caches the modules, and the superrequest module has been modified to work correctly
        //with oauth already. We get a new verions by appending some other characters to defeat the cache.
        if(global.OAUTH)
            request = require('.\\super-request');
        else
            headers["Authorization"] = 'Basic:' + new Buffer('RobCIsNot:AUserOnThisLRS').toString('base64'); //note bad encoding here.
            request(helper.getEndpointAndAuth())
            .put(helper.getEndpointStatements() + '?statementId=' + data.id)
            .headers(headers)
            .json(data)
            .expect(401, done);
    });
})

/**  XAPI-00335, Communication 2.1.3 GET Statements
 * An LRS must support HTTP Basic Authentication
 */
 //WARNING: This might not be a great test. OAUTH will override it
    it('An LRS must support HTTP Basic Authentication(Authentication 4.0 XAPI-00335)', function(done)
    {
        var templates = [
        {
            statement: '{{statements.default}}'
        }];
        var data = helper.createFromTemplate(templates);
        data = data.statement;
        data.id = helper.generateUUID();
        var headers = helper.addAllHeaders(
        {});

        request(helper.getEndpointAndAuth())
            .put(helper.getEndpointStatements() + '?statementId=' + data.id)
            .headers(headers)
            .json(data)
            .expect(204, done);
    });

}(module, require('fs'), require('extend'), require('moment'), require('super-request'), require('supertest-as-promised'), require('chai'), require('url'), require('joi'), require('./../helper'), require('./../multipartParser'), require('./../redirect.js')));<commit_msg>don't run these tests when in oauth mode<commit_after>(function(module, fs, extend, moment, request, requestPromise, chai, liburl, Joi, helper, multipartParser, redirect)
{
	if (global.OAUTH)
	{
		/**  XAPI-00334, Communication 2.1.3 GET Statements
		 * An LRS rejects a Statement of bad authorization (either authentication needed or failed credentials) with error code 401 Unauthorized
		 */
		describe('An LRS rejects a Statement of bad authorization (either authentication needed or failed credentials) with error code 401 Unauthorized (Authentication 4.0 XAPI-00334)', function()
		{

			it("fails when given a random name pass pair", function(done)
			{
				var templates = [
				{
					statement: '{{statements.default}}'
				}];
				var data = helper.createFromTemplate(templates);
				data = data.statement;
				data.id = helper.generateUUID();
				var headers = helper.addAllHeaders(
				{});

				//warning: this ".\\" is super important. Node caches the modules, and the superrequest module has been modified to work correctly
				//with oauth already. We get a new verions by appending some other characters to defeat the cache.
				if (global.OAUTH)
					request = require('.\\super-request');
				else
					headers["Authorization"] = 'Basic ' + new Buffer('RobCIsNot:AUserOnThisLRS').toString('base64');
				request(helper.getEndpointAndAuth())
					.put(helper.getEndpointStatements() + '?statementId=' + data.id)
					.headers(headers)
					.json(data)
					.expect(401, done);
			});

			it('fails with a malformed header', function(done)
			{
				var templates = [
				{
					statement: '{{statements.default}}'
				}];
				var data = helper.createFromTemplate(templates);
				data = data.statement;
				data.id = helper.generateUUID();
				var headers = helper.addAllHeaders(
				{});

				//warning: this ".\\" is super important. Node caches the modules, and the superrequest module has been modified to work correctly
				//with oauth already. We get a new verions by appending some other characters to defeat the cache.
				if (global.OAUTH)
					request = require('.\\super-request');
				else
					headers["Authorization"] = 'Basic:' + new Buffer('RobCIsNot:AUserOnThisLRS').toString('base64'); //note bad encoding here.
				request(helper.getEndpointAndAuth())
					.put(helper.getEndpointStatements() + '?statementId=' + data.id)
					.headers(headers)
					.json(data)
					.expect(401, done);
			});
		})

		/**  XAPI-00335, Communication 2.1.3 GET Statements
		 * An LRS must support HTTP Basic Authentication
		 */
		//WARNING: This might not be a great test. OAUTH will override it
		it('An LRS must support HTTP Basic Authentication(Authentication 4.0 XAPI-00335)', function(done)
		{
			var templates = [
			{
				statement: '{{statements.default}}'
			}];
			var data = helper.createFromTemplate(templates);
			data = data.statement;
			data.id = helper.generateUUID();
			var headers = helper.addAllHeaders(
			{});

			request(helper.getEndpointAndAuth())
				.put(helper.getEndpointStatements() + '?statementId=' + data.id)
				.headers(headers)
				.json(data)
				.expect(204, done);
		});
	}
}(module, require('fs'), require('extend'), require('moment'), require('super-request'), require('supertest-as-promised'), require('chai'), require('url'), require('joi'), require('./../helper'), require('./../multipartParser'), require('./../redirect.js')));<|endoftext|>