Mirage JS Deep Dive: ทำความเข้าใจเกี่ยวกับโรงงาน อุปกรณ์การแข่งขัน และ Serializers (ตอนที่ 2)

เผยแพร่แล้ว: 2022-03-10
สรุปอย่างย่อ ↬ ในส่วนที่สองของซีรีส์ Mirage JS Deep Dive เราจะพิจารณาโรงงาน การแข่งขัน และอนุกรมของ Mirage JS เราจะมาดูกันว่าพวกเขาเปิดใช้งานการเยาะเย้ย API อย่างรวดเร็วโดยใช้ Mirage ได้อย่างไร

ในบทความก่อนหน้าของชุดนี้ เราได้ศึกษาโมเดลและความสัมพันธ์ที่เกี่ยวข้องกับ Mirage ฉันอธิบายว่าโมเดลช่วยให้เราสร้างข้อมูลจำลองแบบไดนามิกที่ Mirage จะให้บริการกับแอปพลิเคชันของเราเมื่อส่งคำขอไปยังปลายทางจำลองของเรา ในบทความนี้ เราจะพิจารณาคุณสมบัติอื่นๆ ของ Mirage อีกสามประการที่ช่วยให้การจำลอง API รวดเร็วยิ่งขึ้น มาดำดิ่งกันเลย!

หมายเหตุ : ฉันขอแนะนำให้อ่านบทความสองบทความแรกของฉัน หากคุณยังไม่สามารถจัดการกับสิ่งที่จะกล่าวถึงในที่นี้ได้เป็นอย่างดี อย่างไรก็ตาม คุณยังคงติดตามและอ้างอิงบทความก่อนหน้านี้ได้เมื่อจำเป็น

  • การตั้งค่า API จำลองด้วย Mirage JS และ Vue
  • โมเดลและสมาคม Mirage JS

โรงงาน

ในบทความที่แล้ว ฉันได้อธิบายว่า Mirage JS ใช้เพื่อจำลองแบ็กเอนด์ API อย่างไร ตอนนี้ สมมติว่าเรากำลังเยาะเย้ยทรัพยากรผลิตภัณฑ์ใน Mirage เพื่อให้บรรลุสิ่งนี้ เราจะสร้าง ตัวจัดการเส้นทาง ซึ่งจะรับผิดชอบในการสกัดกั้นคำขอไปยังจุดปลายใดจุดหนึ่ง และในกรณีนี้ จุดสิ้นสุดคือ api/products ตัวจัดการเส้นทางที่เราสร้างจะส่งคืนผลิตภัณฑ์ทั้งหมด ด้านล่างนี้คือรหัสเพื่อให้บรรลุสิ่งนี้ใน Mirage:

 import { Server, Model } from 'miragejs'; new Server({ models: { product: Model, }, routes() { this.namespace = "api"; this.get('products', (schema, request) => { return schema.products.all() }) } }); },

ผลลัพธ์ข้างต้นจะเป็น:

 { "products": [] }

เราเห็นจากผลลัพธ์ด้านบนว่าทรัพยากรผลิตภัณฑ์ว่างเปล่า อย่างไรก็ตาม เป็นไปตามที่คาดไว้ เนื่องจากเรายังไม่ได้สร้างบันทึกใดๆ

เคล็ดลับแบบมือโปร : Mirage ให้ชวเลขที่จำเป็นสำหรับจุดปลาย API แบบเดิม ดังนั้นตัวจัดการเส้นทางด้านบนอาจสั้นเท่ากับ: this.get('/products')

เพิ่มเติมหลังกระโดด! อ่านต่อด้านล่าง↓

มาสร้างบันทึกของโมเดล product เพื่อเก็บไว้ในฐานข้อมูล Mirage โดยใช้เมธอด seeds บน Server ของเรา:

 seeds(server) { server.create('product', { name: 'Gemini Jacket' }) server.create('product', { name: 'Hansel Jeans' }) },

ผลลัพธ์:

 { "products": [ { "name": "Gemini Jacket", "id": "1" }, { "name": "Hansel Jeans", "id": "2" } ] }

ดังที่คุณเห็นด้านบน เมื่อแอปพลิเคชันส่วนหน้าของเราส่งคำขอไปยัง /api/products ก็จะได้รับคอลเล็กชันของผลิตภัณฑ์ตามที่กำหนดไว้ในวิธี seeds กลับคืนมา

การใช้วิธี seeds ในการ seed ฐานข้อมูลของ Mirage เป็นขั้นตอนที่ไม่ต้องสร้างแต่ละรายการเป็นอ็อบเจกต์ด้วยตนเอง อย่างไรก็ตาม การสร้างบันทึกผลิตภัณฑ์ใหม่ 1,000 (หรือหนึ่งล้าน) รายการโดยใช้รูปแบบข้างต้นนั้นไม่ใช่เรื่องจริง จึงมีความต้องการ โรงงาน

โรงงานอธิบาย

โรงงานเป็นวิธีที่เร็วกว่าในการสร้างบันทึกฐานข้อมูลใหม่ ช่วยให้เราสามารถสร้างเร็กคอร์ดหลายรายการของโมเดลหนึ่งๆ ได้อย่างรวดเร็ว พร้อมรูปแบบต่างๆ ที่จะจัดเก็บไว้ในฐานข้อมูล Mirage JS

โรงงานยังเป็นวัตถุที่ช่วยให้สร้างข้อมูลที่ดูสมจริงได้ง่ายโดยไม่ต้องแยกข้อมูลเหล่านั้นทีละรายการ โรงงานเป็นมากกว่า สูตร หรือ พิมพ์เขียว สำหรับการสร้างบันทึกจากแบบจำลอง

การสร้างโรงงาน

มาตรวจสอบโรงงานโดยสร้างโรงงานกันเถอะ โรงงานที่เราจะสร้างจะถูกใช้เป็นพิมพ์เขียวสำหรับการสร้างผลิตภัณฑ์ใหม่ในฐานข้อมูล Mirage JS ของเรา

 import { Factory } from 'miragejs' new Server({ // including the model definition for a better understanding of what's going on models: { product: Model }, factories: { product: Factory.extend({}) } })

จากด้านบน คุณจะเห็นว่าเราเพิ่มคุณสมบัติ factories ในอินสแตนซ์ Server ของเราและกำหนดคุณสมบัติอื่นภายในนั้นตามแบบแผนที่มีชื่อเดียวกับรุ่นที่เราต้องการสร้างโรงงานสำหรับ ในกรณีนี้ โมเดลนั้นคือ รุ่น product . ตัวอย่างข้างต้นแสดงให้เห็นรูปแบบที่คุณจะปฏิบัติตามเมื่อสร้างโรงงานใน Mirage JS

แม้ว่าเราจะมีโรงงานสำหรับรุ่น product แต่เรายังไม่ได้เพิ่มคุณสมบัติเข้าไปจริงๆ คุณสมบัติของโรงงานอาจเป็นประเภทธรรมดาๆ เช่น strings บูลี นหรือ ตัวเลข หรือ ฟังก์ชัน ที่ส่งคืนข้อมูลไดนามิกดังที่เราเห็นในการใช้งานอย่างเต็มรูปแบบของโรงงานผลิตภัณฑ์ใหม่ของเราด้านล่าง:

 import { Server, Model, Factory } from 'miragejs' new Server({ models: { product: Model }, factories: { product: Factory.extend({ name(i) { // i is the index of the record which will be auto incremented by Mirage JS return `Awesome Product ${i}`; // Awesome Product 1, Awesome Product 2, etc. }, price() { let minPrice = 20; let maxPrice = 2000; let randomPrice = Math.floor(Math.random() * (maxPrice - minPrice + 1)) + minPrice; return `$ ${randomPrice}`; }, category() { let categories = [ 'Electronics', 'Computing', 'Fashion', 'Gaming', 'Baby Products', ]; let randomCategoryIndex = Math.floor( Math.random() * categories.length ); let randomCategory = categories[randomCategoryIndex]; return randomCategory; }, rating() { let minRating = 0 let maxRating = 5 return Math.floor(Math.random() * (maxRating - minRating + 1)) + minRating; }, }), }, })

ในข้อมูลโค้ดด้านบนนี้ เรากำลังระบุลอจิกจาวาสคริปต์บางส่วนผ่าน Math.random เพื่อสร้างข้อมูลไดนามิกทุกครั้งที่โรงงานถูกใช้เพื่อสร้างเรกคอร์ดผลิตภัณฑ์ใหม่ ซึ่งแสดงถึงความแข็งแกร่งและความยืดหยุ่นของโรงงาน

มาสร้างผลิตภัณฑ์โดยใช้โรงงานที่เรากำหนดไว้ข้างต้นกัน ในการทำเช่นนั้น เราเรียก server.create และส่งต่อชื่อรุ่น ( product ) เป็นสตริง มิราจจะสร้างบันทึกใหม่ของผลิตภัณฑ์โดยใช้โรงงานผลิตภัณฑ์ที่เรากำหนด รหัสที่คุณต้องการเพื่อทำสิ่งต่อไปนี้:

 new Server({ seeds(server) { server.create("product") } })

คำแนะนำอย่างมืออาชีพ : คุณสามารถเรียกใช้ console.log(server.db.dump()) เพื่อดูบันทึกในฐานข้อมูลของ Mirage

เร็กคอร์ดใหม่ที่คล้ายกับด้านล่างถูกสร้างขึ้นและจัดเก็บไว้ในฐานข้อมูล Mirage

 { "products": [ { "rating": 3, "category": "Computing", "price": "$739", "name": "Awesome Product 0", "id": "1" } ] }

เอาชนะโรงงาน

เราสามารถแทนที่ค่าบางส่วนหรือมากกว่าที่โรงงานกำหนดโดยการส่งผ่านอย่างชัดเจนดังนี้:

 server.create("product", {name: "Yet Another Product", rating: 5, category: "Fashion" })

บันทึกผลลัพธ์จะคล้ายกับ:

 { "products": [ { "rating": 5, "category": "Fashion", "price": "$782", "name": "Yet Another Product", "id": "1" } ] }

createList

เมื่อมีโรงงานอยู่แล้ว เราสามารถใช้เมธอดอื่นบนอ็อบเจ็กต์เซิร์ฟเวอร์ที่ชื่อว่า createList วิธีนี้ช่วยให้สามารถสร้างเร็กคอร์ดหลายรายการของแบบจำลองหนึ่งๆ โดยส่งผ่านชื่อรุ่นและจำนวนเรคคอร์ดที่คุณต้องการสร้าง ด้านล่างนี้คือการใช้งาน:

 server.createList("product", 10)

หรือ

 server.createList("product", 1000)

ตามที่คุณสังเกต วิธี createList ด้านบนใช้อาร์กิวเมนต์สองอาร์กิวเมนต์: ชื่อรุ่นเป็นสตริงและจำนวนเต็มบวกที่ไม่เป็นศูนย์ซึ่งแทนจำนวนเรคคอร์ดที่จะสร้าง จากด้านบนนี้ เราเพิ่งสร้างรายการผลิตภัณฑ์ 500 รายการ! รูปแบบนี้มีประโยชน์สำหรับการทดสอบ UI ดังที่คุณจะเห็นในบทความชุดต่อๆ ไปของชุดนี้

การแข่งขัน

ในการทดสอบซอฟต์แวร์ ฟิกซ์เจอร์ หรือ ฟิกซ์ เจอร์ทดสอบคือสถานะของชุดหรือคอลเลกชั่นของอ็อบเจ็กต์ที่ทำหน้าที่เป็นพื้นฐานสำหรับการทดสอบรัน จุดประสงค์หลักของฟิกซ์เจอร์คือเพื่อให้แน่ใจว่าสภาพแวดล้อมการทดสอบเป็นที่รู้จักกันดี เพื่อให้ได้ผลลัพธ์ที่ทำซ้ำได้

Mirage ช่วยให้คุณสร้างส่วนควบและใช้เพื่อเริ่มต้นฐานข้อมูลของคุณด้วยข้อมูลเริ่มต้น

หมายเหตุ : ขอแนะนำให้คุณใช้โรงงาน 9 ใน 10 ครั้ง เนื่องจากจะทำให้หุ่นของคุณบำรุงรักษาได้มากขึ้น

การสร้างการแข่งขัน

มาสร้างฟิกซ์เจอร์ง่ายๆ เพื่อโหลดข้อมูลลงในฐานข้อมูลของเรา:

 fixtures: { products: [ { id: 1, name: 'T-shirts' }, { id: 2, name: 'Work Jeans' }, ], },

ข้อมูลข้างต้นจะถูกโหลดเข้าสู่ฐานข้อมูลโดยอัตโนมัติตามข้อมูลเริ่มต้นของ Mirage อย่างไรก็ตาม หากคุณมีการกำหนดฟังก์ชันเมล็ดพันธุ์ มิราจจะเพิกเฉยต่อการติดตั้งของคุณด้วยสมมติฐานที่คุณตั้งใจจะลบล้างและใช้โรงงานต่างๆ เพื่อเพาะข้อมูลของคุณแทน

ติดตั้งร่วมกับโรงงาน

Mirage จัดเตรียมให้คุณใช้ Fixtures ควบคู่ไปกับ Factory คุณสามารถทำสิ่งนี้ได้โดยการเรียก server.loadFixtures() ตัวอย่างเช่น:

 fixtures: { products: [ { id: 1, name: "iPhone 7" }, { id: 2, name: "Smart TV" }, { id: 3, name: "Pressing Iron" }, ], }, seeds(server) { // Permits both fixtures and factories to live side by side server.loadFixtures() server.create("product") },

ไฟล์ติดตั้ง

ตามหลักการแล้ว คุณจะต้องสร้างส่วนควบในไฟล์แยกจาก server.js และนำเข้า ตัวอย่างเช่น คุณสามารถสร้างไดเร็กทอรีที่เรียกว่า fixtures และในนั้นสร้าง products.js ใน products.js เพิ่ม:

 // <PROJECT-ROOT>/fixtures/products.js export default [ { id: 1, name: 'iPhone 7' }, { id: 2, name: 'Smart TV' }, { id: 3, name: 'Pressing Iron' }, ];

จากนั้นใน server.js นำเข้าและใช้โปรแกรมติดตั้งผลิตภัณฑ์ดังนี้:

 import products from './fixtures/products'; fixtures: { products, },

ฉันกำลังใช้ชวเลขคุณสมบัติ ES6 เพื่อกำหนดอาร์เรย์ผลิตภัณฑ์ที่นำเข้าไปยังคุณสมบัติ products ของวัตถุการแข่งขัน

เป็นเรื่องที่ควรค่าแก่การกล่าวถึงว่าอุปกรณ์ติดตั้ง Mirage JS จะถูกละเว้นในระหว่างการทดสอบ เว้นแต่คุณจะบอกอย่างชัดเจนว่าอย่าทำโดยใช้ server.loadFixtures()

โรงงานเทียบกับการแข่งขัน

ในความคิดของฉัน คุณควรละเว้นจากการใช้อุปกรณ์ยึดติด เว้นแต่คุณมีกรณีการใช้งานเฉพาะที่เหมาะสมกว่าโรงงาน อุปกรณ์ตกแต่งมักจะละเอียดกว่าในขณะที่โรงงานทำงานเร็วกว่าและมีการกดแป้นพิมพ์น้อยกว่า

Serializers

สิ่งสำคัญคือต้องส่งคืนเพย์โหลด JSON ที่คาดว่าจะไปยังส่วนหน้า ด้วยเหตุนี้ serializers

serializer คืออ็อบเจ็กต์ที่รับผิดชอบในการแปลง **โมเดล** หรือ **คอลเล็กชัน** ที่ส่งคืนจากตัวจัดการเส้นทางของคุณเป็นเพย์โหลด JSON ที่มีรูปแบบตามที่แอปส่วนหน้าคาดหวัง

เอกสาร Mirage

ลองใช้ตัวจัดการเส้นทางนี้ตัวอย่างเช่น:

 this.get('products/:id', (schema, request) => { return schema.products.find(request.params.id); });

Serializer มีหน้าที่ในการเปลี่ยนแปลงการตอบสนองต่อสิ่งนี้:

 { "product": { "rating": 0, "category": "Baby Products", "price": "$654", "name": "Awesome Product 1", "id": "2" } }

ซีเรียลไลเซอร์ Mirage JS ในตัว

หากต้องการทำงานกับเครื่องซีเรียลไลเซอร์ Mirage JS คุณจะต้องเลือกว่าตัวสร้างซีเรียลไลเซอร์ในตัวตัวใดที่จะเริ่มต้นด้วย การตัดสินใจนี้จะขึ้นอยู่กับประเภทของ JSON แบ็กเอนด์ของคุณจะส่งไปยังแอปพลิเคชันส่วนหน้าของคุณในที่สุด Mirage มาพร้อมกับ serializers ต่อไปนี้:

  • JSONAPISerializer
    serializer นี้เป็นไปตามข้อกำหนด JSON:API
  • ActiveModelSerializer
    serializer นี้มีจุดประสงค์เพื่อเลียนแบบ API ที่คล้ายกับ Rails API ที่สร้างด้วย active_model_serializer gem
  • RestSerializer
    RestSerializer คือ Mirage JS "catch all" serializer สำหรับ API ทั่วไปอื่นๆ

Serializer คำจำกัดความ

ในการกำหนด serialize ให้นำเข้า serializer ที่เหมาะสม เช่น RestSerializer จาก miragejs ดังนี้:

 import { Server, RestSerializer } from "miragejs"

จากนั้นในอินสแตนซ์ของ Server :

 new Server({ serializers: { application: RestSerializer, }, })

RestSerializer ถูกใช้โดย Mirage JS เป็นค่าเริ่มต้น ดังนั้นจึงซ้ำซ้อนที่จะกำหนดไว้อย่างชัดเจน ตัวอย่างข้างต้นมีไว้เพื่อวัตถุประสงค์ที่เป็นแบบอย่าง

มาดูผลลัพธ์ของทั้ง JSONAPISerializer และ ActiveModelSerializer บนตัวจัดการเส้นทางเดียวกันกับที่เรากำหนดไว้ข้างต้น

JSONAPISซีเรียลไลเซอร์

 import { Server, JSONAPISerializer } from "miragejs" new Server({ serializers: { application: JSONAPISerializer, }, })

ผลลัพธ์:

 { "data": { "type": "products", "id": "2", "attributes": { "rating": 3, "category": "Electronics", "price": "$1711", "name": "Awesome Product 1" } } }

ActiveModelSerializer

หากต้องการดู ActiveModelSerializer ในที่ทำงาน ฉันจะแก้ไขการประกาศ category ในโรงงานผลิตผลิตภัณฑ์เป็น:

 productCategory() { let categories = [ 'Electronics', 'Computing', 'Fashion', 'Gaming', 'Baby Products', ]; let randomCategoryIndex = Math.floor( Math.random() * categories.length ); let randomCategory = categories[randomCategoryIndex]; return randomCategory; },

ทั้งหมดที่ฉันทำคือเปลี่ยนชื่อของคุณสมบัติเป็น productCategory เพื่อแสดงว่า serializer จะจัดการกับมันอย่างไร

จากนั้น เรากำหนด ActiveModelSerializer serializer ดังนี้:

 import { Server, ActiveModelSerializer } from "miragejs" new Server({ serializers: { application: ActiveModelSerializer, }, })

serializer แปลง JSON ที่ส่งคืนเป็น:

 { "rating": 2, "product_category": "Computing", "price": "$64", "name": "Awesome Product 4", "id": "5" }

คุณจะสังเกตเห็นว่า productCategory ถูกเปลี่ยนเป็น product_category ซึ่งสอดคล้องกับ active_model_serializer gem ของระบบนิเวศ Ruby

การปรับแต่ง Serializers

Mirage ให้ความสามารถในการปรับแต่งซีเรียลไลเซอร์ สมมติว่าแอปพลิเคชันของคุณต้องการให้ชื่อแอตทริบิวต์ของคุณเป็นแบบอูฐ คุณสามารถแทนที่ RestSerializer เพื่อให้บรรลุเป้าหมายนั้น เราจะใช้ไลบรารียูทิลิตี้ lodash :

 import { RestSerializer } from 'miragejs'; import { camelCase, upperFirst } from 'lodash'; serializers: { application: RestSerializer.extend({ keyForAttribute(attr) { return upperFirst(camelCase(attr)); }, }), },

สิ่งนี้ควรสร้าง JSON ของแบบฟอร์ม:

 { "Rating": 5, "ProductCategory": "Fashion", "Price": "$1386", "Name": "Awesome Product 4", "Id": "5" }

ห่อ

คุณทำมัน! หวังว่าคุณจะมีความเข้าใจอย่างลึกซึ้งเกี่ยวกับ Mirage ผ่านบทความนี้ และคุณยังได้เห็นแล้วว่าการใช้โรงงาน อุปกรณ์ติดตั้ง และ Serializers จะช่วยให้คุณสร้าง API Mocks ที่เหมือนกับการใช้งานจริงได้มากขึ้นด้วย Mirage ได้อย่างไร

  • ส่วนที่ 1: ทำความเข้าใจกับโมเดลและความสัมพันธ์ของ Mirage JS
  • ส่วนที่ 2: ทำความเข้าใจเกี่ยวกับโรงงาน อุปกรณ์ติดตั้ง และตัวระบุลำดับ
  • ส่วนที่ 3: ทำความเข้าใจเกี่ยวกับเวลา การตอบสนอง และการส่งผ่าน
  • ส่วนที่ 4: การใช้ Mirage JS และ Cypress สำหรับการทดสอบ UI