mirror of
https://github.com/andwati/zitadel.git
synced 2026-10-18 05:52:51 +00:00
<!-- Please inform yourself about the contribution guidelines on submitting a PR here: https://github.com/zitadel/zitadel/blob/main/CONTRIBUTING.md#submit-a-pull-request-pr. Take note of how PR/commit titles should be written and replace the template texts in the sections below. Don't remove any of the sections. It is important that the commit history clearly shows what is changed and why. Important: By submitting a contribution you agree to the terms from our Licensing Policy as described here: https://github.com/zitadel/zitadel/blob/main/LICENSING.md#community-contributions. --> # Which Problems Are Solved - This adds rudimentary country code handling for LoginV1 SMS OTP - Previously defaulting to CH with no prompt to user causing e.g UK (+44) based numbers to be re-routed to CH. (+41) # Additional Context - Support for SMS OTP is not complete for LoginV2 (according to latest support email) Tested with Twilio on both UK + DE # . Appears to work. - Closes #8891 <img width="544" height="485" alt="image" src="https://github.com/user-attachments/assets/84d31bd8-8863-465f-8860-b51602439dfb" /> <img width="858" height="1298" alt="Screenshot 2026-01-16 at 11 23 22" src="https://github.com/user-attachments/assets/4bf16f0b-2fec-4d63-95b0-f0b73f3a131a" /> --------- Co-authored-by: Livio Spring <[email protected]> Co-authored-by: Silvan <[email protected]>
224 lines
4.7 KiB
Go
224 lines
4.7 KiB
Go
package domain
|
|
|
|
import (
|
|
"sort"
|
|
"strings"
|
|
"testing"
|
|
|
|
"golang.org/x/text/language"
|
|
|
|
"github.com/zitadel/zitadel/internal/zerrors"
|
|
)
|
|
|
|
func TestFormatPhoneNumber(t *testing.T) {
|
|
type args struct {
|
|
phone *Phone
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
result *Phone
|
|
errFunc func(err error) bool
|
|
}{
|
|
{
|
|
name: "invalid phone number",
|
|
args: args{
|
|
phone: &Phone{
|
|
PhoneNumber: "PhoneNumber",
|
|
},
|
|
},
|
|
errFunc: zerrors.IsErrorInvalidArgument,
|
|
},
|
|
{
|
|
name: "format phone 071...",
|
|
args: args{
|
|
phone: &Phone{
|
|
PhoneNumber: "0711234567",
|
|
},
|
|
},
|
|
result: &Phone{
|
|
PhoneNumber: "+41711234567",
|
|
},
|
|
},
|
|
{
|
|
name: "format phone 0041...",
|
|
args: args{
|
|
phone: &Phone{
|
|
PhoneNumber: "0041711234567",
|
|
},
|
|
},
|
|
result: &Phone{
|
|
PhoneNumber: "+41711234567",
|
|
},
|
|
},
|
|
{
|
|
name: "format phone 071 xxx xx xx",
|
|
args: args{
|
|
phone: &Phone{
|
|
PhoneNumber: "071 123 45 67",
|
|
},
|
|
},
|
|
result: &Phone{
|
|
PhoneNumber: "+41711234567",
|
|
},
|
|
},
|
|
{
|
|
name: "format phone +4171 xxx xx xx",
|
|
args: args{
|
|
phone: &Phone{
|
|
PhoneNumber: "+4171 123 45 67",
|
|
},
|
|
},
|
|
result: &Phone{
|
|
PhoneNumber: "+41711234567",
|
|
},
|
|
},
|
|
{
|
|
name: "format phone 004171 xxx xx xx",
|
|
args: args{
|
|
phone: &Phone{
|
|
PhoneNumber: "004171 123 45 67",
|
|
},
|
|
},
|
|
result: &Phone{
|
|
PhoneNumber: "+41711234567",
|
|
},
|
|
},
|
|
{
|
|
name: "format non swiss phone 004371 xxx xx xx",
|
|
args: args{
|
|
phone: &Phone{
|
|
PhoneNumber: "004371 123 45 67",
|
|
},
|
|
},
|
|
result: &Phone{
|
|
PhoneNumber: "+43711234567",
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
normalized, err := tt.args.phone.PhoneNumber.Normalize()
|
|
if tt.errFunc == nil && tt.result.PhoneNumber != normalized {
|
|
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.PhoneNumber, normalized)
|
|
}
|
|
if tt.errFunc != nil && !tt.errFunc(err) {
|
|
t.Errorf("got wrong err: %v ", err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetCountryCodes(t *testing.T) {
|
|
codes := GetCountryCodes(language.English)
|
|
|
|
t.Run("returns non-empty list", func(t *testing.T) {
|
|
if len(codes) == 0 {
|
|
t.Error("GetCountryCodes() returned empty list")
|
|
}
|
|
})
|
|
|
|
t.Run("returns more than 200 countries", func(t *testing.T) {
|
|
// libphonenumber supports 240+ regions
|
|
if len(codes) < 200 {
|
|
t.Errorf("GetCountryCodes() returned %d countries, expected at least 200", len(codes))
|
|
}
|
|
})
|
|
|
|
t.Run("list is sorted by name", func(t *testing.T) {
|
|
sorted := sort.SliceIsSorted(codes, func(i, j int) bool {
|
|
return codes[i].Name < codes[j].Name
|
|
})
|
|
if !sorted {
|
|
t.Error("GetCountryCodes() did not return a list sorted by name")
|
|
}
|
|
})
|
|
|
|
t.Run("all entries have valid format", func(t *testing.T) {
|
|
for _, code := range codes {
|
|
if code.ISOCode == "" {
|
|
t.Errorf("country code has empty ISOCode: %+v", code)
|
|
}
|
|
if len(code.ISOCode) < 2 {
|
|
t.Errorf("country code has invalid ISOCode length: %+v", code)
|
|
}
|
|
if !strings.HasPrefix(code.CallingCode, "+") {
|
|
t.Errorf("country code CallingCode does not start with '+': %+v", code)
|
|
}
|
|
if code.Name == "" {
|
|
t.Errorf("country code has empty Name: %+v", code)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestGetCountryCodes_ContainsExpectedCountries(t *testing.T) {
|
|
codes := GetCountryCodes(language.English)
|
|
|
|
// Build a map for easier lookup
|
|
codeMap := make(map[string]CountryCode)
|
|
for _, code := range codes {
|
|
codeMap[code.ISOCode] = code
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
isoCode string
|
|
callingCode string
|
|
countryName string
|
|
}{
|
|
{
|
|
name: "United States",
|
|
isoCode: "US",
|
|
callingCode: "+1",
|
|
countryName: "United States",
|
|
},
|
|
{
|
|
name: "Switzerland",
|
|
isoCode: "CH",
|
|
callingCode: "+41",
|
|
countryName: "Switzerland",
|
|
},
|
|
{
|
|
name: "United Kingdom",
|
|
isoCode: "GB",
|
|
callingCode: "+44",
|
|
countryName: "United Kingdom",
|
|
},
|
|
{
|
|
name: "Germany",
|
|
isoCode: "DE",
|
|
callingCode: "+49",
|
|
countryName: "Germany",
|
|
},
|
|
{
|
|
name: "Australia",
|
|
isoCode: "AU",
|
|
callingCode: "+61",
|
|
countryName: "Australia",
|
|
},
|
|
{
|
|
name: "Japan",
|
|
isoCode: "JP",
|
|
callingCode: "+81",
|
|
countryName: "Japan",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
code, found := codeMap[tt.isoCode]
|
|
if !found {
|
|
t.Errorf("GetCountryCodes() does not contain %s (%s)", tt.name, tt.isoCode)
|
|
return
|
|
}
|
|
if code.CallingCode != tt.callingCode {
|
|
t.Errorf("GetCountryCodes() %s CallingCode = %s, want %s", tt.isoCode, code.CallingCode, tt.callingCode)
|
|
}
|
|
if code.Name != tt.countryName {
|
|
t.Errorf("GetCountryCodes() %s Name = %s, want %s", tt.isoCode, code.Name, tt.countryName)
|
|
}
|
|
})
|
|
}
|
|
}
|