Merge pull request #31010 from woocommerce/add/run-api-tests-on-pr

Run API tests on PR with e2e tests
This commit is contained in:
Ron Rennick 2021-11-05 09:12:26 -03:00 committed by GitHub
commit efe7e4f8ba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 276 additions and 6 deletions

View File

@ -75,4 +75,9 @@ jobs:
WC_E2E_SCREENSHOTS: 1
E2E_SLACK_TOKEN: ${{ secrets.E2E_SLACK_TOKEN }}
E2E_SLACK_CHANNEL: ${{ secrets.E2E_SLACK_CHANNEL }}
run: pnpx wc-e2e test:e2e
BASE_URL: ${{ secrets.PR_E2E_TEST_URL }}
USER_KEY: ${{ secrets.PR_E2E_TEST_ADMIN_USER }}
USER_SECRET: ${{ secrets.PR_E2E_TEST_ADMIN_PASSWORD }}
run: |
pnpx wc-e2e test:e2e
pnpx wc-api-tests test api

View File

@ -0,0 +1,19 @@
/**
* A basic refund.
*
* For more details on the order refund properties, see:
*
* https://woocommerce.github.io/woocommerce-rest-api-docs/#order-refund-properties
*
*/
const refund = {
api_refund: false,
amount: '1.00',
reason: 'Late delivery refund.',
line_items: [],
};
module.exports = {
refund: refund,
};

View File

@ -0,0 +1,60 @@
/**
* Internal dependencies
*/
const {
getRequest,
postRequest,
deleteRequest,
} = require( '../utils/request' );
/**
* WooCommerce Refunds endpoints.
*
* https://woocommerce.github.io/woocommerce-rest-api-docs/#refunds
*/
const refundsApi = {
name: 'Refunds',
create: {
name: 'Create a refund',
method: 'POST',
path: 'orders/<id>/refunds',
responseCode: 201,
refund: async ( orderId, refundDetails ) =>
postRequest( `orders/${ orderId }/refunds`, refundDetails ),
},
retrieve: {
name: 'Retrieve a refund',
method: 'GET',
path: 'orders/<id>/refunds/<refund_id>',
responseCode: 200,
refund: async ( orderId, refundId ) =>
getRequest( `orders/${ orderId }/refunds/${ refundId }` ),
},
listAll: {
name: 'List all refunds',
method: 'GET',
path: 'orders/<id>/refunds',
responseCode: 200,
refunds: async ( orderId ) =>
getRequest( `orders/${ orderId }/refunds` ),
},
delete: {
name: 'Delete a refund',
method: 'DELETE',
path: 'orders/<id>/refunds/<refund_id>',
responseCode: 200,
payload: {
force: false,
},
refund: async ( orderId, refundId, deletePermanently ) =>
deleteRequest(
`orders/${ orderId }/refunds/${ refundId }`,
deletePermanently
),
},
};
module.exports = {
refundsApi: refundsApi,
};

View File

@ -0,0 +1,122 @@
const { refundsApi } = require( '../../endpoints/refunds' );
const { ordersApi } = require( '../../endpoints/orders' );
const { productsApi } = require( '../../endpoints/products' );
const { refund } = require( '../../data' );
/**
* Tests for the WooCommerce Refunds API.
*
* @group api
* @group refunds
*
*/
describe( 'Refunds API tests', () => {
let expectedRefund;
let orderId;
let productId;
beforeAll( async () => {
// Create a product and save its product ID
const product = {
name: 'Simple Product for Refunds API tests',
regular_price: '100',
};
const createProductResponse = await productsApi.create.product(
product
);
productId = createProductResponse.body.id;
// Create an order with a product line item, and save its Order ID
const order = {
status: 'pending',
line_items: [
{
product_id: productId,
},
],
};
const createOrderResponse = await ordersApi.create.order( order );
orderId = createOrderResponse.body.id;
// Setup the expected refund object
expectedRefund = {
...refund,
line_items: [
{
product_id: productId,
},
],
};
} );
afterAll( async () => {
// Cleanup the created product and order
await productsApi.delete.product( productId, true );
await ordersApi.delete.order( orderId, true );
} );
it( 'can create a refund', async () => {
const { status, body } = await refundsApi.create.refund(
orderId,
expectedRefund
);
expect( status ).toEqual( refundsApi.create.responseCode );
expect( body.id ).toBeDefined();
// Save the refund ID
expectedRefund.id = body.id;
// Verify that the order was refunded.
const getOrderResponse = await ordersApi.retrieve.order( orderId );
expect( getOrderResponse.body.refunds ).toHaveLength( 1 );
expect( getOrderResponse.body.refunds[ 0 ].id ).toEqual(
expectedRefund.id
);
expect( getOrderResponse.body.refunds[ 0 ].reason ).toEqual(
expectedRefund.reason
);
expect( getOrderResponse.body.refunds[ 0 ].total ).toEqual(
`-${ expectedRefund.amount }`
);
} );
it( 'can retrieve a refund', async () => {
const { status, body } = await refundsApi.retrieve.refund(
orderId,
expectedRefund.id
);
expect( status ).toEqual( refundsApi.retrieve.responseCode );
expect( body.id ).toEqual( expectedRefund.id );
} );
it( 'can list all refunds', async () => {
const { status, body } = await refundsApi.listAll.refunds( orderId );
expect( status ).toEqual( refundsApi.listAll.responseCode );
expect( body ).toHaveLength( 1 );
expect( body[ 0 ].id ).toEqual( expectedRefund.id );
} );
it( 'can delete a refund', async () => {
const { status, body } = await refundsApi.delete.refund(
orderId,
expectedRefund.id,
true
);
expect( status ).toEqual( refundsApi.delete.responseCode );
expect( body.id ).toEqual( expectedRefund.id );
// Verify that the refund cannot be retrieved
const retrieveRefundResponse = await refundsApi.retrieve.refund(
orderId,
expectedRefund.id
);
expect( retrieveRefundResponse.status ).toEqual( 404 );
// Verify that the order no longer has a refund
const retrieveOrderResponse = await ordersApi.retrieve.order( orderId );
expect( retrieveOrderResponse.body.refunds ).toHaveLength( 0 );
} );
} );

View File

@ -12,7 +12,7 @@ const getCoreTestsRoot = require( '../../core-tests-root' );
/**
* External dependencies
*/
const { it, describe, beforeAll } = require( '@jest/globals' );
const { it, describe, beforeAll, afterAll } = require( '@jest/globals' );
const path = require( 'path' );
const coreTestsPath = getCoreTestsRoot();
@ -103,6 +103,15 @@ const runImportProductsTest = () => {
await merchant.openAllProductsView();
await merchant.openImportProducts();
} );
afterAll(async () => {
// Delete imported products
await withRestApi.deleteAllProducts();
await withRestApi.deleteAllProductAttributes();
await withRestApi.deleteAllProductCategories();
await withRestApi.deleteAllProductTags();
});
it( 'should show error message if you go without providing CSV file', async () => {
// Verify the error message if you go without providing CSV file
await Promise.all( [
@ -212,9 +221,6 @@ const runImportProductsTest = () => {
expect( productPrices.sort() ).toEqual(
productPricesOverride.sort()
);
// Delete imported products
await withRestApi.deleteAllProducts();
} );
} );
};

View File

@ -1,7 +1,7 @@
/**
* Internal dependencies
*/
const { merchant } = require('@woocommerce/e2e-utils');
const { merchant, withRestApi } = require('@woocommerce/e2e-utils');
const { lorem, helpers } = require('faker');
const runAddShippingClassesTest = () => {
@ -13,6 +13,10 @@ const runAddShippingClassesTest = () => {
await merchant.openSettings('shipping', 'classes');
});
afterAll(async () => {
await withRestApi.deleteAllShippingClasses();
});
it('can add shipping classes', async () => {
const shippingClassSlug = {
name: lorem.words(),

View File

@ -5,6 +5,7 @@
- `utils.waitForTimeout( delay )` pause processing for `delay` milliseconds
- `AdminEdit` class with utility functions for the respective edit screens
- Update `shopper.addToCartFromShopPage()` and `.removeFromCart()` to accept product Id or Title
- Added `deleteAllProductAttributes()`, `deleteAllProductCategories()`, and `deleteAllProductTags()` to clean up meta data added when products are imported
- Added `withRestApi.createProductCategory()` that creates a product category and returns the ID
# 0.1.6

View File

@ -154,6 +154,9 @@ Please note: if you're using a non-SSL environment (such as a Docker container f
| `updateSettingOption` | `settingsGroup`, `settingID`, `payload` | Update a settings group |
| `updatePaymentGateway`| `paymentGatewayId`, `payload` | Update a payment gateway |
| `getSystemEnvironment` | | Get the current environment from the WooCommerce system status API. |
| `deleteAllProductAttributes` | | Permanently delete all product attributes. |
| `deleteAllProductCategories` | | Permanently delete all product categories. |
| `deleteAllProductTags` | | Permanently delete all product tags. |
| `createProductCategory` | `categoryName` | Create a product category with the provided name. |
### Classes

View File

@ -8,6 +8,7 @@ const shippingZoneEndpoint = '/wc/v3/shipping/zones';
const shippingClassesEndpoint = '/wc/v3/products/shipping_classes';
const userEndpoint = '/wp/v2/users';
const systemStatusEndpoint = '/wc/v3/system_status';
const productsEndpoint = '/wc/v3/products';
const productCategoriesEndpoint = '/wc/v3/products/categories';
/**
@ -85,6 +86,55 @@ export const withRestApi = {
const repository = SimpleProduct.restRepository( client );
await deleteAllRepositoryObjects( repository );
},
/**
* Use the API to delete all product attributes.
*
* @return {Promise} Promise resolving once attributes have been deleted.
*/
deleteAllProductAttributes: async () => {
const productAttributesPath = productsEndpoint + '/attributes';
const productAttributes = await client.get( productAttributesPath );
if ( productAttributes.data && productAttributes.data.length ) {
for ( let a = 0; a < productAttributes.data.length; a++ ) {
const response = await client.delete( productAttributesPath + `/${productAttributes.data[a].id}?force=true` );
expect( response.status ).toBe( 200 );
}
}
},
/**
* Use the API to delete all product categories.
*
* @return {Promise} Promise resolving once categories have been deleted.
*/
deleteAllProductCategories: async () => {
const productCategoriesPath = productsEndpoint + '/categories';
const productCategories = await client.get( productCategoriesPath );
if ( productCategories.data && productCategories.data.length ) {
for ( let c = 0; c < productCategories.data.length; c++ ) {
// The default `uncategorized` category can't be deleted
if ( productCategories.data[c].id == 0 ) {
continue;
}
const response = await client.delete( productCategoriesPath + `/${productCategories.data[c].id}?force=true` );
expect( response.status ).toBe( 200 );
}
}
},
/**
* Use the API to delete all product tags.
*
* @return {Promise} Promise resolving once tags have been deleted.
*/
deleteAllProductTags: async () => {
const productTagsPath = productsEndpoint + '/tags';
const productTags = await client.get( productTagsPath );
if ( productTags.data && productTags.data.length ) {
for ( let t = 0; t < productTags.data.length; t++ ) {
const response = await client.delete( productTagsPath + `/${productTags.data[t].id}?force=true` );
expect( response.status ).toBe( 200 );
}
}
},
/**
* Use api package to delete all orders.
*