官术网_书友最值得收藏!

Generating parameterized tests

Some programming languages, such as Java and C#, require special framework support to build parameterized tests. But in JavaScript, we can very easily roll our own parameterization because our test definitions are just function calls. We can use this to our advantage by pulling out each of the existing six tests as functions taking parameter values.

This kind of change requires some diligent refactoring. We'll do the first two tests together, and then you can either repeat for the remaining five tests or jump ahead to the next tag in the Git repository:

  1. Our existing tests use a function named firstNameField. Create a generic version of function that will work for any field, as shown next. It takes a name parameter that must be passed in by the caller to specify which field is being accessed:
const field = name => form('customer').elements[name];
  1. Replace each occurrence of firstNameField() with field('firstName'). You can use find and replace for this.
  2. Run all tests and ensure they are still passing. At this point, you should have 28 passing tests.
  3. Delete the firstNameField function.
  1. Starting with renders as a text box, wrap the entirety of the it call in an arrow function, and then call that function straight after, as shown:
const itRendersAsATextBox = () =>
it('renders as a text box', () => {
render(<CustomerForm />);
expectToBeInputFieldOfTypeText(field('firstName'));
});

itRendersAsATextBox();
  1. Verify that you still have 28 passing tests.
  2. Parameterize this function by promoting the firstName string to a function parameter. You'll then need to pass in the firstName string into the function call itself, as shown here:
const itRendersAsATextBox = (fieldName) =>
it('renders as a text box', () => {
render(<CustomerForm />);
expectToBeInputFieldOfTypeText(field(fieldName));
});

itRendersAsATextBox('firstName');
  1. Again verify that your tests are passing.
  2. Push the itRendersAsATextBox function up one level, and its dependent function, expectToBeInputFieldOfTypeText, into the parent describe scope. That will allow us to use it in subsequent describe blocks.
  3. For the next test, includes the existing value, we can use the same procedure, but this time rather than promoting the string value, Ashley to a parameter, we'll simply replace it with a more generic value. We can do that because the value isn't really important to the test:
We pass in the prop in a generic fashion, using the [fieldName]: syntax to specify the key. This is about as difficult as JSX can get!
const itIncludesTheExistingValue = (fieldName) =>
it('includes the existing value', () => {
render(<CustomerForm { ...{[fieldName]: 'value'} } />);
expect(field(fieldName).value).toEqual('value');
});

itIncludesTheExistingValue('firstName');
  1. Verify your tests are passing and then push itIncludesTheExistingValue up one level, into the parent describe scope.
  2. Repeat steps 5-9 for the remaining four tests. As a hint, the next test for the label will need a second parameter for the label text, and the two tests for submitting existing values and new values will need a second parameter, for the value.
    For reference, here's how the final test might end up looking:
const itSubmitsNewValue = (fieldName, value) =>
it('saves new value when submitted', async () => {
expect.hasAssertions();
render(
<CustomerForm
{ ...{[fieldName]: 'existingValue'} }
onSubmit={props =>
expect(props[fieldName]).toEqual(value)
}
/>);
await ReactTestUtils.Simulate.change(field(fieldName), {
target: { value }
});
await ReactTestUtils.Simulate.submit(form('customer'));
});

itSubmitsNewValue('firstName', 'firstName');

With all that done, your describe block will now quite succinctly describe what the first name field does:

describe('first name field', () => {
itRendersAsATextBox('firstName');
itIncludesTheExistingValue('firstName');
itRendersALabel('firstName', 'First name');
itAssignsAnIdThatMatchesTheLabelId('firstName');
itSubmitsExistingValue('firstName', 'firstName');
itSubmitsNewValue('firstName', 'anotherFirstName');
});
主站蜘蛛池模板: 南丹县| 封丘县| 鄂托克前旗| 大宁县| 静乐县| 玛多县| 城固县| 博白县| 蒙阴县| 时尚| 汕尾市| 五原县| 天等县| 阿尔山市| 伊金霍洛旗| 合江县| 电白县| 牡丹江市| 赤峰市| 舞阳县| 西乡县| 武安市| 庆元县| 耒阳市| 黑水县| 台东市| 涡阳县| 得荣县| 邢台市| 霍州市| 西充县| 阆中市| 安化县| 钟山县| 蚌埠市| 大化| 思南县| 高要市| 北票市| 彰武县| 宁河县|