Giter Club home page Giter Club logo

Comments (9)

annewanghy avatar annewanghy commented on June 22, 2024

VSCode 忽略搜索哪些文件夹

"search.exclude": {
    "**/.git": true,
    "**/build": true,
    "**/node_molecules": true,
    "**/bower_components": true,
    "**/tmp": true
  }

from annewanghy.github.io.

annewanghy avatar annewanghy commented on June 22, 2024

use Hugo to make a blog
based on go
quicker than Hexo

from annewanghy.github.io.

annewanghy avatar annewanghy commented on June 22, 2024

frontend/containers/product/index.tsx

Product.getInitialProps = ({
  query,
  context
}: InitialProps): Promise<ProductProps> => {
  const productCode: api.IProductCode = { code: (query && query.code) || "" };

  if (!productCode.code) {
    throw errNotFound;
  }

  const service = makeService(api.ProductService, context);

  return service.getProduct(productCode).then(productResponse => {
    if (!productResponse.product) {
      throw errNotFound;
    }

    const properties: base.IProperty[] =
      (productResponse.product && productResponse.product.filterProperties) ||
      [];

    const topLevelCategory: base.IProperty = properties.find(
      ({ field }) => field === "TopLevelCategory"
    ) || { values: [] };

    const filterProperties: products.IFilterProperty[] = [
      {
        field: "TopLevelCategory",
        groupType: products.FilterGroupType.PRODUCT,
        inValues: topLevelCategory.values
      }
    ];

    return service
      .filterProducts({ filterProperties, page: 1, perPage: 5 })
      .then(({ result, rdGroups }) => {
        const products = ((result && result.products) || [])
          .filter(({ code }) => code !== productCode.code)
          .slice(0, 4);

        const productsResponse: api.IProductsResponse = {
          products,
          rdGroups
        };

        return {
          productResponse,
          productsResponse
        } as ProductProps;
      });
  });
};

api/products.proto
api.ProductService
上面用到了GetProduct (ProductCode) returns (ProductResponse)这个方法

service ProductService {
  rpc GetProduct (ProductCode) returns (ProductResponse);
  rpc GetProducts (ProductCodes) returns (ProductsResponse);
  rpc GetFilterGroups (products.SearchOptions) returns (FilterProductsResponse);
  rpc FilterProducts (products.SearchOptions) returns (FilterProductsResponse);
}

没有找到,就throw一个errorNotFound的错误, 输出错误信息product not found

const errNotFound = new ProductNotFound(404);

class ProductNotFound extends Error {
  constructor(public statusCode: number) {
    super("product not found");
  }
}

frontend/proto.d.ts文件里面可以找到base.IProperty

export namespace base {

    /** Properties of a Property. */
    interface IProperty {

        /** Property field */
        field?: string;

        /** Property values */
        values?: string[];
    }
...
}
/** for filter products */
namespace products下的interface IProduct有这个过滤属性,类型就是base.IProperty
filterProperties?: base.IProperty[];  
const properties: base.IProperty[] =
   (productResponse.product && productResponse.product.filterProperties) ||
   [];
而base.IProperty是namespace base下的interface IProperty,这个接口需要两个可选参数filed,和values
const topLevelCategory: base.IProperty = properties.find(
   ({ field }) => field === "TopLevelCategory") || { values: [] };
 设置过滤条件为*TopLevelCategory*, 需要修改为*TopLevelCollection*
 const filterProperties: products.IFilterProperty[] = [
      {
        field: "TopLevelCategory",
        groupType: products.FilterGroupType.PRODUCT,
        inValues: topLevelCategory.values
      }
    ];

class SearchOptions { //选择条件
 class AggregateCondition {//合计条件
  interface IFilterProperty { // 过滤属性
        /** FilterProperty field */
        field?: string;

        /** FilterProperty groupType */
        groupType?: products.FilterGroupType;

        /** FilterProperty inValues */
        inValues?: string[];

        /** FilterProperty isNegative */
        isNegative?: boolean;
    }
 }
}
return service
      .filterProducts({ filterProperties, page: 1, perPage: 5 }) // 用到了page, perPage和filterProperties三个可选参数
      .then(({ result, rdGroups }) => {// 用到了返回函数的result和rdGroups两个参数
        const products = ((result && result.products) || [])  // 得到返回的结果是result.products
          .filter(({ code }) => code !== productCode.code)
          .slice(0, 4);

        const productsResponse: api.IProductsResponse = {
          products,
          rdGroups
        };

        return {
          productResponse,
          productsResponse
        } as ProductProps;
      });
ProductService{
  //返回一个Promise对象
 public filterProducts(request: products.ISearchOptions): Promise<api.FilterProductsResponse>;
}

输入参数
products.ISearchOptions
/** Properties of a SearchOptions. */
    interface ISearchOptions {

        /** SearchOptions keyword */
        keyword?: string;

        /** SearchOptions page */
        page?: (number|Long);

        /** SearchOptions perPage */
        perPage?: (number|Long);

        /** SearchOptions filterProperties */
        filterProperties?: products.IFilterProperty[];

        /** SearchOptions sorters */
        sorters?: products.ISorter[];

        /** SearchOptions conditions */
        conditions?: products.FilterCondition[];

        /** SearchOptions filterGroups */
        filterGroups?: products.ISearchFilterGroup[];

        /** SearchOptions filterGroupMode */
        filterGroupMode?: products.SearchFilterGroupMode;

        /** SearchOptions path */
        path?: string;

        /** SearchOptions publishReady */
        publishReady?: (number|Long);

        /** SearchOptions scheduledAt */
        scheduledAt?: string;
    }

返回参数
class FilterProductsResponse {

        /**
         * Constructs a new FilterProductsResponse.
         * @param [properties] Properties to set
         */
        constructor(properties?: api.IFilterProductsResponse);

        /** FilterProductsResponse result. */
        public result?: (products.IFilterProductsResult|null);

        /** FilterProductsResponse rdGroups. */
        public rdGroups: referencedata.IRDGroup[];
 ...
}

/** Properties of a FilterProductsResult. */
    interface IFilterProductsResult {

        /** FilterProductsResult products */
        products?: products.IProduct[];

        /** FilterProductsResult filterGroups */
        filterGroups?: products.IFilterGroup[];

        /** FilterProductsResult total */
        total?: (number|Long);
    }

from annewanghy.github.io.

annewanghy avatar annewanghy commented on June 22, 2024

主要是解决将topLevelCategory换成topLevelCollection的问题

frontend/product/productField.ts

enum ProductField {
  TopLevelCategory = "TopLevelCategory",
  SubCategory = "SubCategory",
  Collection = "Collection",
  Material = "Material",
  ColorDescription = "ColorDescription",
  Size = "Size",
  TotalLength = "TotalLength",
  MaximumWidth = "MaximumWidth"
}
TopLevelCategory
{"categories":{"items":[{"itemType":"TopLevelCategory","code":"TC1","slug":"earrings","name":"ピアス(イヤリング)","description":"多くの文化で身分や美しさの象徴として用いられている。かつては、奴隷身分を示すため、耳から外すことのできないタイプのものが用いられていたところもある。","images":[{"device":"MOBILE","url":"//mastani-dev.s3-ap-southeast-1.amazonaws.com/reference_data_item_images/6/image/key-visual-1.20171109052617018896809.png"},{"device":"LAPTOP","url":"//mastani-dev.s3-ap-southeast-1.amazonaws.com/reference_data_item_images/5/image/key-visual.20171109054317787731532.png","purpose":"earrings category"}]},{"itemType":"TopLevelCategory","code":"TC2","slug":"rings","name":"リング"},{"itemType":"TopLevelCategory","code":"TC3","slug":"necklace","name":"ネックレス"},{"itemType":"TopLevelCategory","code":"TC4","slug":"bracelet","name":"ブレスレット"},{"itemType":"TopLevelCategory","code":"TC5","slug":"brooch","name":"ブローチ"},{"itemType":"TopLevelCategory","code":"TC6","slug":"pendant","name":"ペンダント"},{"itemType":"TopLevelCategory","code":"TC7","slug":"brooch","name":"ブローチ"},{"itemType":"TopLevelCategory","code":"TC8","slug":"accessories","name":"アクセサリー","images":[{"device":"MOBILE","url":"//mastani-dev.s3.ap-southeast-1.amazonaws.com/reference_data_item_images/1/image/anime-like-fate-stay-night.20171102081417498370912.jpg","purpose":"collection page"}]}]},"isOnCartPage":false}

frontend/index.ts

const CollectionList = (limit?: number) => {
  const List = ((props: Props) => (
    <Responsive>
      {(desktop: boolean) =>
        desktop ? <DesktopList {...props} /> : <MobileList {...props} />}
    </Responsive>
  )) as Container<Props>;

  List.getInitialProps = ({ context }: InitialProps): Promise<Props> =>
    makeService(api.ReferenceDataService, context)
      .getItems({ fetchAll: true, itemType: "Collection" })
      .then(({ items }) => {
        items = items.filter(
          ({ images }) => images != null && images.length > 0
        );

        if (limit != null) {
          items = items.slice(0, limit);
        }

        return { items };
      });

  return List;
};

TopLevelCategory

{filterProperties: Array(1), page: 1, perPage: 5}
filterProperties:Array(1)
field:"TopLevelCategory"
groupType:0
inValues:"TC1"

Collection

{filterProperties: Array(1), page: 1, perPage: 5}
filterProperties:Array(1)
field:"Collection"
groupType:0
inValues:["CL4"]

但是最后和Jaden讨论之后,明白产品没有collection这个属性,而是用TopLevelCategory.
那就是不需要修改原来junhui写的内容

from annewanghy.github.io.

annewanghy avatar annewanghy commented on June 22, 2024

学习怎么使用postman调用后台数据
导入团队开发的.json文件,然后换到collection的tab页面,发送send请求就可以获取API的数据

本地的API数据 http://localhost:9800/api/ja/api.ProductService/FilterProducts
更换为远程的API数据 https://mastani-api.dt.theplant-dev.com/api/ja/api.ProductService/FilterProducts

image

image

from annewanghy.github.io.

annewanghy avatar annewanghy commented on June 22, 2024

Promise没有完成
product/index.test.tsx
现在的写法用then来调用filter是错误的,因此还需要修改
半成品

import Product from ".";
import { ProductProps } from "./mobile";
import { api, products, base } from "../../proto";
import { productResponse, productsResponse } from "./fakeData";
import { testContext } from "../../testHelper";

const properties: base.IProperty[] =
  (productResponse.product && productResponse.product.filterProperties) ||
  [];

const topLevelCategory: base.IProperty = properties.find(
  ({ field }) => field === "TopLevelCategory"
) || { values: [] };

const filterProperties: products.IFilterProperty[] = [
  {
    field: "TopLevelCategory",
    groupType: products.FilterGroupType.PRODUCT,
    inValues: topLevelCategory.values
  }
];

describe("Product.getInitialProps", () => {
  test("happy filter path", async () => {
    const response: typeof api.ProductService.prototype.getProduct(productResponse.product.code) = () => 
      Promise
        .resolve(new api.ProductResponse(productResponse))
        .then(() => {
            const filterResponse: typeof api.ProductService.prototype.filterProducts({ filterProperties, page: 1, perPage: 5 })= () => 
                Promise.resolve(new api.FilterProductsResponse(productsResponse))
        })

    api.ProductService.prototype.getProduct = jest.fn(response);

    const props = await Product.getInitialProps(testContext());

    const expected: ProductProps = { productResponse: productResponse, productsResponse: productsResponse};

    expect(props).toMatchObject(expected);
  });

  test("failing filter API call", () => {
    const error = new Error("test error");

    api.ProductService.prototype.filterProducts = jest.fn(() =>
      Promise.reject(error)
    );

    expect.hasAssertions();

    return expect(Product.getInitialProps(testContext())).rejects.toBe(error);
  });

  test("failing API call", () => {
    const error = new Error("test error");

    api.ProductService.prototype.getProduct = jest.fn(() =>
      Promise.reject(error)
    );

    expect.hasAssertions();

    return expect(Product.getInitialProps(testContext())).rejects.toBe(error);
  });
});

from annewanghy.github.io.

annewanghy avatar annewanghy commented on June 22, 2024
import Product from ".";
import { ProductProps } from "./mobile";
import { api } from "../../proto";
import { productResponse, productsResponse } from "./fakeData";
import { testContext } from "../../testHelper";

describe("Product.getInitialProps", () => {
  test("happy path", async () => {
    const getProductResponse: typeof api.ProductService.prototype.getProduct = () =>
      Promise.resolve(new api.ProductResponse(productResponse));

    const getProductsResponse: typeof api.ProductService.prototype.getFilterGroups = () =>
      Promise.resolve(new api.FilterProductsResponse(productsResponse));

    api.ProductService.prototype.getProduct = jest.fn(getProductResponse);
    api.ProductService.prototype.getFilterGroups = jest.fn(getProductsResponse);

    const props = await Product.getInitialProps({
      ...testContext(),
      query: { code: "xxx" }
    });

    const expected: ProductProps = {
      productResponse: productResponse,
      productsResponse: productsResponse
    };

    expect(props).toMatchObject(expected);
  });

  test("failing API call", () => {
    const error = new Error("test error");

    api.ProductService.prototype.getProduct = jest.fn(() =>
      Promise.reject(error)
    );

    api.ProductService.prototype.getFilterGroups = jest.fn(() =>
      Promise.reject(error)
    );

    expect.hasAssertions();

    return expect(
      Product.getInitialProps({ ...testContext(), query: { code: "xxx" } })
    ).rejects.toBe(error);
  });
});

from annewanghy.github.io.

annewanghy avatar annewanghy commented on June 22, 2024

总共12个case

  • error
    • without code - > throw errorNotFound
    • make service error
    • service.getProduct error
    • service.filterProducts error
  • no error
    • filterProperties[0].inValues
      • dosen't has topLevelCategory.values
      • has topLevelCategory.values
    • filterProducts
      • filterProducts dosen't contain product
      • filterProducts contain product
        • filterProducts === null, productsResponse = null
        • filterProducts.length in (1,4) , productsResponse = filterProducts.length
        • filterProducts.length >4 , productsResponse = 4

from annewanghy.github.io.

annewanghy avatar annewanghy commented on June 22, 2024

first try

import Product from ".";
import { ProductProps } from "./mobile";
import { api } from "../../proto";
import {
  productResponse,
  filterProductsResponse,
  filteredProductsResponse
} from "./fakeData";
import { testContext } from "../../testHelper";

describe("throw error", () => {
  test("fail to get product code", () => {
    const error = new Error("fail to get product code");

    expect.hasAssertions();

    return expect(
      Product.getInitialProps({
        ...testContext()
      })
    ).rejects.toEqual(error);
  });
  test("fail to make service", () => {
    const error = new RangeError("index out of range: 5 + 4 > 7");

    expect.hasAssertions();

    return expect(
      Product.getInitialProps({
        ...testContext(),
        query: {
          code: "ES-43"
        }
      })
    ).rejects.toEqual(error);
  });

  test("fail to call api getProduct", () => {
    const error = new Error("getProduct error");

    api.ProductService.prototype.getProduct = jest.fn(() =>
      Promise.reject(error)
    );

    expect.hasAssertions();

    return expect(
      Product.getInitialProps({
        ...testContext(),
        query: {
          code: "ES-43"
        }
      })
    ).rejects.toEqual(error);
  });

  test("fail to call api getFilterGroups", () => {
    const error = new Error("getProduct error");

    api.ProductService.prototype.getFilterGroups = jest.fn(() =>
      Promise.reject(error)
    );

    expect.hasAssertions();

    return expect(
      Product.getInitialProps({
        ...testContext(),
        query: {
          code: "ES-43"
        }
      })
    ).rejects.toEqual(error);
  });

  test("failing API call", () => {
    const error = new Error("test error");

    api.ProductService.prototype.getProduct = jest.fn(() =>
      Promise.reject(error)
    );

    api.ProductService.prototype.getFilterGroups = jest.fn(() =>
      Promise.reject(error)
    );

    expect.hasAssertions();

    return expect(
      Product.getInitialProps({
        ...testContext(),
        query: {
          code: "ES-43"
        }
      })
    ).rejects.toEqual(error);
  });
});

describe("Product.getInitialProps", () => {
  test("happy path", async () => {
    const getProductResponse: typeof api.ProductService.prototype.getProduct = () =>
      Promise.resolve(new api.ProductResponse(productResponse));

    const getFilterProductsResponse: typeof api.ProductService.prototype.filterProducts = () =>
      Promise.resolve(new api.FilterProductsResponse(filterProductsResponse));

    api.ProductService.prototype.getProduct = jest.fn(getProductResponse);
    api.ProductService.prototype.filterProducts = jest.fn(
      getFilterProductsResponse
    );

    const props = await Product.getInitialProps({
      ...testContext(),
      query: {
        code: "ES-43"
      }
    });

    const expected: ProductProps = {
      productResponse: productResponse,
      productsResponse: filteredProductsResponse
    };

    expect(props).toMatchObject(expected);
  });
});

describe("test filter data", () => {
  const cases: Array<
    [string, string | null, Array<String> | null, {} | any]
  > = [
    [
      "filtered products don't contain the product",
      "ES-00",
      ["ES-01", "ES-02", "ES-03"],
      ["ES-01", "ES-02", "ES-03"]
    ],
    [
      "filtered products contain the product",
      "ES-00",
      ["ES-00", "ES-01", "ES-02"],
      ["ES-01", "ES-02"]
    ],
    ["filtered products = null", null, null, null],
    [
      "filtered products's length <= 4 and doesn't contain product",
      "ES-00",
      ["ES-01"],
      ["ES-01"]
    ],
    [
      "filtered products'length>4 and doesn't contain the product",
      "ES-00",
      ["ES-01", "ES-02", "ES-03", "ES-04", "ES-05"],
      ["ES-01", "ES-02", "ES-03", "ES-04"]
    ]
  ];

  cases.forEach(([desc, productCode, filterProduct, filteredProduct]) => {
    test(`${desc}`, () => {
      var filterProductResult: Array<String> | null = new Array();
      if (filterProduct && filterProduct.length <= 4) {
        filterProductResult = ((filterProduct && filterProduct) || []).filter(
          product => product !== productCode
        );
      } else {
        filterProductResult = ((filterProduct && filterProduct) || [])
          .filter(product => product !== productCode)
          .slice(0, 4);
      }

      expect(filterProductResult).toMatchObject(filteredProduct);
    });
  });
});

两个错误“Expected at least one assertion to be called but received none.”
一个不匹配

from annewanghy.github.io.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.